<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Chris Sainty</title>
    <description>The latest articles on DEV Community by Chris Sainty (@chrissainty).</description>
    <link>https://dev.to/chrissainty</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F185290%2Fb332e56f-aaeb-481e-9fca-24d078f8f5eb.jpeg</url>
      <title>DEV Community: Chris Sainty</title>
      <link>https://dev.to/chrissainty</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chrissainty"/>
    <language>en</language>
    <item>
      <title>Building a simple tooltip component for Blazor in under 10 lines of code*</title>
      <dc:creator>Chris Sainty</dc:creator>
      <pubDate>Tue, 06 Oct 2020 14:32:27 +0000</pubDate>
      <link>https://dev.to/chrissainty/building-a-simple-tooltip-component-for-blazor-in-under-10-lines-of-code-10ai</link>
      <guid>https://dev.to/chrissainty/building-a-simple-tooltip-component-for-blazor-in-under-10-lines-of-code-10ai</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KPXoek6K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/10/simple-tooltip-component-for-blaor-in-under-10-lines-of-code.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KPXoek6K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/10/simple-tooltip-component-for-blaor-in-under-10-lines-of-code.jpg" alt="Building a simple tooltip component for Blazor in under 10 lines of code*"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It has been so long since I've managed to get some time to write a blog post. Since my last post, I've been working hard writing the first few chapters for my book, Blazor in Action – which should be out on MEAP (Manning Early Access Program)  very very soon. My wife and I also had our first child at the start of September which has been an amazing and interesting new challenge to take on. I'm loving every minute so far but I'm sooo thankful for my coffee machine!!&lt;/p&gt;

&lt;p&gt;Anyway, back to the subject in hand, in this post I'm going to be showing you how you can build a really simple, reusable, tooltip component for your Blazor applications. I've used a bit of artistic license with the title of this post, while it's less than 10 lines of Razor, that doesn't include the CSS. But as the CSS will be minified at some point I don't think it should count.... Anyway, moving on.&lt;/p&gt;

&lt;p&gt;If you're just interested in the result, then you can &lt;a href="https://github.com/chrissainty/SimpleBlazorTooltip"&gt;check out the GitHub repo&lt;/a&gt; which has the final working version of the code in this post. I also want to point out that I've used the .NET5 preview bits to build this so you will need those installed to run the sample.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Tooltip component
&lt;/h2&gt;

&lt;p&gt;The first thing we're going to do is create a new component called &lt;em&gt;Tooltip.razor&lt;/em&gt; and add the following code:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="tooltip-wrapper"&amp;gt;
    &amp;lt;span&amp;gt;@Text&amp;lt;/span&amp;gt;
    @ChildContent
&amp;lt;/div&amp;gt;

@code {
    [Parameter] public RenderFragment ChildContent { get; set; }
    [Parameter] public string Text { get; set; }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The component has two parameters, &lt;code&gt;ChildContent&lt;/code&gt; and &lt;code&gt;Text&lt;/code&gt;. When we use the component, it's going to wrap the markup where we want the tooltip to display. The wrapped markup will be captured by the &lt;code&gt;ChildContent&lt;/code&gt; parameter and displayed inside the main &lt;code&gt;div&lt;/code&gt; of our tooltip. The other parameter &lt;code&gt;Text&lt;/code&gt;, is what we will use to set the text that the tooltip will display.&lt;/p&gt;

&lt;p&gt;That's all there is in terms of Razor code! Not bad, 9 lines including a space. The real magic to making this all work is in the CSS. I'm using the new .NET5 RC1 bits and with that I can take advantage of Blazor's new CSS isolation feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding the CSS
&lt;/h2&gt;

&lt;p&gt;To use CSS isolation in Blazor we need to create a CSS file with the same name as the component the styles are used by. In our case the component is called, &lt;em&gt;Tooltip.razor&lt;/em&gt;. So our stylesheet needs to be called &lt;em&gt;Tooltip.razor.css&lt;/em&gt;. Once this is done we can add the following styles:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.tooltip-wrapper {
    position: relative;
    display: inline-block;
    border-bottom: 1px dotted black;
    cursor: help;
}

span {
    visibility: hidden;
    position: absolute;
    width: 120px;
    bottom: 100%;
    left: 50%;
    margin-left: -60px;
    background-color: #363636;
    color: #fff;
    text-align: center;
    padding: 5px 0;
    border-radius: 6px;
    z-index: 1;
}

span::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    margin-left: -5px;
    border-width: 5px;
    border-style: solid;
    border-color: #555 transparent transparent transparent;
}

.tooltip-wrapper:hover span {
    visibility: visible;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first class, &lt;code&gt;.tooltip-wrapper&lt;/code&gt; is applied to the container div of the component. It makes the div render as &lt;code&gt;inline-block&lt;/code&gt; so the document flow isn't disrupted. It also sets it's position as relative. This means we can then absolute position the child span (tooltip text) where we need, relative to the parent div. The final two rules add some styling to show the user there is a tooltip available.&lt;/p&gt;

&lt;p&gt;The next set of styles apply to the &lt;code&gt;span&lt;/code&gt; element, this contains the tooltip text that will be shown. By default, the span is hidden and it's absolutely positioned relative to the parent div. With the styles shown above, the tooltip will be shown above the content which is contained between the start and end tags of the Tooltip component.&lt;/p&gt;

&lt;p&gt;The next style is what is called a pseudo element. This is going to add an element to the DOM. What this style does is create a small arrow at the bottom of the tooltip text pointing to the content that the tooltip is wrapping.&lt;/p&gt;

&lt;p&gt;The final style will show the span containing the tooltip text whenever the user hovers over the parent div with their cursor.&lt;/p&gt;

&lt;p&gt;That's all there is to it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the Tooltip
&lt;/h2&gt;

&lt;p&gt;In order to use the tooltip, just wrap it around the content you want the user to be able to hover over to show the tooltip text, and add whatever message you want to be displayed. If all goes well it should look something like this...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Da6jpfaJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/10/simple-tooltip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Da6jpfaJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/10/simple-tooltip.png" alt="Building a simple tooltip component for Blazor in under 10 lines of code*"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Just to recap, in this post I showed you how you can create a simple reusable tooltip component for your Blazor application. The whole component was only 9 lines of Razor code, require no JavaScript, and about 36 lines of CSS. We also had a chance to use the new CSS isolation feature which will be shipping in .NET 5 which is right around the corner.&lt;/p&gt;

&lt;p&gt;This was a much shorter post than I normally write but it's just nice to actually write a blog post again! I hope to be announcing the MEAP for Blazor in Action any day now so as soon as that is available I will have a blog post up about it and how you can get your hands on it.&lt;/p&gt;

</description>
      <category>blazor</category>
      <category>webdev</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Creating a Custom Validation Message Component for Blazor Forms</title>
      <dc:creator>Chris Sainty</dc:creator>
      <pubDate>Tue, 30 Jun 2020 08:14:07 +0000</pubDate>
      <link>https://dev.to/chrissainty/creating-a-custom-validation-message-component-for-blazor-forms-139o</link>
      <guid>https://dev.to/chrissainty/creating-a-custom-validation-message-component-for-blazor-forms-139o</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kwqQSyrb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/06/creating-a-custom-validation-message-component-for-blazor-forms.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kwqQSyrb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/06/creating-a-custom-validation-message-component-for-blazor-forms.jpg" alt="Creating a Custom Validation Message Component for Blazor Forms"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As some of you may know, I'm a big fan of Tailwind CSS. If you've not heard of Tailwind before then please checkout my previous posts about it which can be found &lt;a href="https://dev.to/chrissainty/integrating-tailwind-css-with-blazor-using-gulp-part-1-4k6g"&gt;here&lt;/a&gt; and &lt;a href="https://dev.to/chrissainty/integrating-tailwind-css-with-blazor-using-gulp-part-2-435i"&gt;here&lt;/a&gt;. The reason I mention this is because when I was using it on a recent Blazor project, I hit a bit of a snag. I wanted to style my validation messages using Tailwinds utility classes, but I couldn't add them to the component. This is because the &lt;code&gt;ValidationMessage&lt;/code&gt; component adds a hard-coded class which can't be added to or overriden.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.OpenElement(0, "div");
builder.AddMultipleAttributes(1, AdditionalAttributes);
builder.AddAttribute(2, "class", "validation-message");
builder.AddContent(3, message);
builder.CloseElement();

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The full source can be viewed &lt;a href="https://github.com/dotnet/aspnetcore/blob/master/src/Components/Web/src/Forms/ValidationMessage.cs"&gt;here&lt;/a&gt;, but as you can see in the snippet above, while the component supports passing additional attributes, the component will always override any &lt;code&gt;class&lt;/code&gt; attribute that is supplied.&lt;/p&gt;

&lt;p&gt;I could've added a wrapper &lt;code&gt;div&lt;/code&gt; around each usage of &lt;code&gt;ValidationMessage&lt;/code&gt; and added my classes there, but that felt like a clunky solution. I've also seen several people in the community asking about customising the output of the &lt;code&gt;ValidationSummary&lt;/code&gt; component. So I thought this would be a good opportunity to come up with a better way.&lt;/p&gt;

&lt;p&gt;In this post, I'm going to show how you can create a &lt;code&gt;ValidationMessage&lt;/code&gt; component with customisable UI. I'll start by showing a more simplistic approach and then show a more robust and reusable solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does ValidationMessage work?
&lt;/h2&gt;

&lt;p&gt;Before we get into the solutions, I wanted to quickly cover how the standard &lt;code&gt;ValidationMessage&lt;/code&gt; works.&lt;/p&gt;

&lt;p&gt;The default component is pretty compact weighing in at about 100 lines of code. It accepts a cascaded &lt;code&gt;EditContext&lt;/code&gt; and adds an event handler for the &lt;code&gt;OnValidationStateChanged&lt;/code&gt; event. All this handler does is call &lt;code&gt;StateHasChanged&lt;/code&gt; whenever the event fires.&lt;/p&gt;

&lt;p&gt;It also creates a &lt;code&gt;FieldIdentifier&lt;/code&gt; based on whichever model property has been specified via the &lt;code&gt;For&lt;/code&gt; parameter. This is then used when calling the &lt;code&gt;GetValidationMessages&lt;/code&gt; method on the &lt;code&gt;EditContext&lt;/code&gt;. This method will return all of the current validation error messages for the given &lt;code&gt;FieldIdentifier&lt;/code&gt;. Any messages returned are then rendered.&lt;/p&gt;

&lt;p&gt;In summary, the componet does three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listens for changes to the validation state&lt;/li&gt;
&lt;li&gt;Retrieves any validation messages for the model property specified&lt;/li&gt;
&lt;li&gt;Displays the messages on screen&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we understand what the original component does, let's move on to the solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a simple replacement
&lt;/h2&gt;

&lt;p&gt;The first option, which was pretty quick to build, was largly a modified version of the original component.&lt;/p&gt;

&lt;p&gt;The default component caters for a lot of potential scenarios, things like dynamically changing &lt;code&gt;EditContext&lt;/code&gt;'s or updates to the &lt;code&gt;For&lt;/code&gt; parameter. Therefore there's a lot of code which is checking and caching values to support this and be as efficient as possible.&lt;/p&gt;

&lt;p&gt;However, my use case was very straightforward, just a standard form which wouldn't have anything dynamically changing. This mean't that I could do away with a good amount of code. The result is the following.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@using System.Linq.Expressions

@typeparam TValue
@implements IDisposable

@foreach (var message in EditContext.GetValidationMessages(_fieldIdentifier))
{
    &amp;lt;div class="@Class"&amp;gt;
        @message
    &amp;lt;/div&amp;gt;
}

@code {
    [CascadingParameter] private EditContext EditContext { get; set; }

    [Parameter] public Expression&amp;lt;Func&amp;lt;TValue&amp;gt;&amp;gt; For { get; set; }
    [Parameter] public string Class { get; set; }

    private FieldIdentifier _fieldIdentifier;

    protected override void OnInitialized()
    {
        _fieldIdentifier = FieldIdentifier.Create(For);
        EditContext.OnValidationStateChanged += HandleValidationStateChanged;
    }

    private void HandleValidationStateChanged(object o, ValidationStateChangedEventArgs args) =&amp;gt; StateHasChanged();

    public void Dispose()
    {
        EditContext.OnValidationStateChanged -= HandleValidationStateChanged;
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I implemented the same fundamental behavor as the original component, I created a &lt;code&gt;FieldIdentifier&lt;/code&gt; based on the model property defined via the &lt;code&gt;For&lt;/code&gt; parameter. Registered a handler for the &lt;code&gt;OnValidationStateChanged&lt;/code&gt; event on &lt;code&gt;EdiContext&lt;/code&gt;. I also unregistered it to avoid any memory leaks by implementing &lt;code&gt;IDisposable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In my markup, I then output any validation messages as per the original component, but with one simple difference. I removed the hard-coded CSS applied and added a &lt;code&gt;Class&lt;/code&gt; parameter. Now I could provide any classes I wanted to apply on a case by case basis. Here's an example of usage.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;CustomValidationMessage For="@(() =&amp;gt; _model.FirstName)"
                         Class="mt-2 sm:ml-4 font-semibold text-red-600" /&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This implementation resolved the original issue, I could now use my Tailwind CSS classes to style my validation messages without any issues. Job done, right?&lt;/p&gt;

&lt;p&gt;For my immediate problem, yes. But it got me thinking about some of those comments from the community I mentioned in the introduction. In those comments, developers were asking about changing the HTML that was rendered, not just adding custom CSS classes. This solution doesn't help with that problem. This lead me to create my second solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  ValidationMessageBase for ultimate customisation
&lt;/h2&gt;

&lt;p&gt;I really love the approach the Blazor team took with building the input components for forms. Providing us with &lt;code&gt;InputBase&amp;lt;T&amp;gt;&lt;/code&gt; is great as we can focus on building custom UI, which is what needs to be changed in 99% of cases, while the boilerplate of integrating with the form and validation system is taken care of.&lt;/p&gt;

&lt;p&gt;Wouldn't it be great if there was something like that for validation messages as well...?&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating ValidationMessageBase
&lt;/h3&gt;

&lt;p&gt;By creating a base class for validation messages, as per the design of the input components, it would give developers the freedom to tweak the UI output to their exact needs. Here's the code.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ValidationMessageBase&amp;lt;TValue&amp;gt; : ComponentBase, IDisposable
{
    private FieldIdentifier _fieldIdentifier;

    [CascadingParameter] private EditContext EditContext { get; set; }
    [Parameter] public Expression&amp;lt;Func&amp;lt;TValue&amp;gt;&amp;gt; For { get; set; }
    [Parameter] public string Class { get; set; }

    protected IEnumerable&amp;lt;string&amp;gt; ValidationMessages =&amp;gt; EditContext.GetValidationMessages(_fieldIdentifier);

    protected override void OnInitialized()
    {
        _fieldIdentifier = FieldIdentifier.Create(For);
        EditContext.OnValidationStateChanged += HandleValidationStateChanged;
    }

    private void HandleValidationStateChanged(object o, ValidationStateChangedEventArgs args) =&amp;gt; StateHasChanged();

    public void Dispose()
    {
        EditContext.OnValidationStateChanged -= HandleValidationStateChanged;
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is essentially the logic from the code block in the first solution, except I've added a property which returns the current validation messages instead of calling the &lt;code&gt;GetValidationMessages&lt;/code&gt; method directly on the &lt;code&gt;EditContext&lt;/code&gt;. This is purely to make the developer experience a little nicer when implementing markup for the validation messages.&lt;/p&gt;

&lt;p&gt;With this base class I can implement the same markup as I had for the first solutions really easily.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@typeparam TValue
@inherits ValidationMessageBase&amp;lt;TValue&amp;gt;

@foreach (var message in ValidationMessages)
{
    &amp;lt;div class="@Class"&amp;gt;
        @message
    &amp;lt;/div&amp;gt;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And if I want to implement something different in a future project all I need to do is create a new derived component.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@typeparam TValue
@inherits ValidationMessageBase&amp;lt;TValue&amp;gt;

@if (ValidationMessages.Any())
{
    &amp;lt;ul class="validation-errors"&amp;gt;
        @foreach (var message in ValidationMessages)
        {
            &amp;lt;li class="validation-error-message"&amp;gt;
                @message
            &amp;lt;/li&amp;gt;
        }
    &amp;lt;/ul&amp;gt;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this post, I've show a limitation with the default &lt;code&gt;ValidationMessage&lt;/code&gt; component which comes with Blazor, specifically, the inability to customise the markup it produces. I've shown two potential solutions.&lt;/p&gt;

&lt;p&gt;The first is a modified version of the original component. The hard-coded styling was removed and replaced with a &lt;code&gt;Class&lt;/code&gt; parameter allowing CSS classes to be specified per usage.&lt;/p&gt;

&lt;p&gt;The second solution was based on the design of Blazors input components. A base class was used to abstract away the boilerplate code, allowing developers to focus on creating the specific markup they require, for ultimate flexability.&lt;/p&gt;

</description>
      <category>blazor</category>
      <category>webdev</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Avoiding AccessTokenNotAvailableException when using the Blazor WebAssembly Hosted template with individual user accounts</title>
      <dc:creator>Chris Sainty</dc:creator>
      <pubDate>Tue, 09 Jun 2020 08:00:00 +0000</pubDate>
      <link>https://dev.to/chrissainty/avoiding-accesstokennotavailableexception-when-using-the-blazor-webassembly-hosted-template-with-individual-user-accounts-37a7</link>
      <guid>https://dev.to/chrissainty/avoiding-accesstokennotavailableexception-when-using-the-blazor-webassembly-hosted-template-with-individual-user-accounts-37a7</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--71yXRaXs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/06/AccessTokenNotAvailableException-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--71yXRaXs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/06/AccessTokenNotAvailableException-1.jpg" alt="Avoiding AccessTokenNotAvailableException when using the Blazor WebAssembly Hosted template with individual user accounts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Blazor WebAssembly has shipped with a host of new options for authentication. We now have the ability to create Blazor Wasm apps which can authenticate against Active Directory, Azure AD, Azure AD B2C, Identity Server, in fact any OIDC provider should work with Blazor. But, there is a little gotcha which has tripped a few people up when building applications which mix protected and unprotected endpoints using the Blazor WebAssembly ASP.NET Core Hosted template with Individual user accounts enabled.&lt;/p&gt;

&lt;p&gt;The default configuration in the template uses an HTTP client with a custom message handler called &lt;code&gt;BaseAddressAuthorizationMessageHandler&lt;/code&gt;. This handler attempts to attach an access token to any outgoing requests and if it can't find one, it throws an exception.&lt;/p&gt;

&lt;p&gt;This makes sense if you're only calling protected endpoints, but if your application allows the user to call &lt;strong&gt;unprotected endpoints without logging in&lt;/strong&gt; then you might see a &lt;code&gt;AccessTokenNotAvailableException&lt;/code&gt; in the browser console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7LQn6Hgm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/06/AccessTokenNotAvailableException.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7LQn6Hgm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/06/AccessTokenNotAvailableException.jpg" alt="Avoiding AccessTokenNotAvailableException when using the Blazor WebAssembly Hosted template with individual user accounts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this post, I'm going to show you how to configure an additional &lt;code&gt;HttpClient&lt;/code&gt; instance which can be used by unauthenticated users to call unprotected endpoints, avoiding an &lt;code&gt;AccessTokenNotAvailableException&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Default Configuration
&lt;/h2&gt;

&lt;p&gt;When you create a new Blazor WebAssembly application using ASP.NET Core Identity, you'll find the following configuration in the &lt;code&gt;Program.Main&lt;/code&gt; method.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.Services.AddHttpClient("BlazorApp.ServerAPI", client =&amp;gt; client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
                .AddHttpMessageHandler&amp;lt;BaseAddressAuthorizationMessageHandler&amp;gt;();

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This sets up the &lt;code&gt;HttpClient&lt;/code&gt; for the application using a custom handler, &lt;code&gt;BaseAddressAuthorizationMessageHandler&lt;/code&gt;. This handler is really useful as it saves us having to worry about adding access tokens to our API requests manually. However, as I explained in the introduction, this is also a potential issue.&lt;/p&gt;

&lt;p&gt;If we delve into the source code, we can see that the &lt;code&gt;BaseAddressAuthorizationMessageHandler&lt;/code&gt; inherits from another class called &lt;code&gt;AuthorizationMessageHandler&lt;/code&gt;, this is the class where we find the potential gotcha.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var tokenResult = _tokenOptions != null ?
                        await _provider.RequestAccessToken(_tokenOptions) :
                        await _provider.RequestAccessToken();

if (tokenResult.TryGetToken(out var token))
{
    _lastToken = token;
    _cachedHeader = new AuthenticationHeaderValue("Bearer", _lastToken.Value);
}
else
{
    throw new AccessTokenNotAvailableException(_navigation, tokenResult, _tokenOptions?.Scopes);
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The piece of code above is looking for a token so it can add it to the authentication header of the outgoing request. And as you can see, if one isn't found then an exception is thrown, &lt;code&gt;AccessTokenNotAvailableExcpetion&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The default template configuration actually gives us a hint of this potential issue on the &lt;code&gt;FetchData&lt;/code&gt; component.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protected override async Task OnInitializedAsync()
{
    try
    {
        forecasts = await Http.GetFromJsonAsync&amp;lt;WeatherForecast[]&amp;gt;("WeatherForecast");
    }
    catch (AccessTokenNotAvailableException exception)
    {
        exception.Redirect();
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There is a &lt;code&gt;try..catch&lt;/code&gt; setup to specifically check for this exception and redirect the user to login.&lt;/p&gt;

&lt;p&gt;Now we can see where the problem comes from, what's the solution?&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring a second HttpClient for unauthenticated requests
&lt;/h2&gt;

&lt;p&gt;The answer is to add a second HTTP Client instance which doesn't use this message handler. We can then use this instance when we want to make unprotected requests, and use the original one for everything else.&lt;/p&gt;

&lt;p&gt;The easiest way we can achieve this is by adding the following line to our &lt;code&gt;Program.Main&lt;/code&gt;.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.Services.AddHttpClient("BlazorApp.PublicServerAPI", client =&amp;gt; client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will add another named HTTP Client instance to our application but, as you can see, there is no special message handler added this time.&lt;/p&gt;

&lt;p&gt;Once this is done, we can get an instance of this client by injecting &lt;code&gt;IHttpClientFactory&lt;/code&gt; into our component or service and using the &lt;code&gt;Create&lt;/code&gt; method with the name of the client.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@inject IHttpClientFactory HttpClientFactory

...

@code {
    private async Task GetSomethingFromAPI()
    {
        var client = HttpClientFactory.Create("BlazorApp.PublicServerAPI");
        var result = client.GetFromJsonAsync&amp;lt;Something&amp;gt;("/api/something");
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Another option, which in my opinion is a bit nicer as I'm not a fan of magic strings, is to create a &lt;em&gt;typed client&lt;/em&gt;. This means we can request an instance by type rather than use the magic string solution.&lt;/p&gt;

&lt;p&gt;To do this we first need to add a new class, we'll call it &lt;code&gt;PublicClient&lt;/code&gt; and add the following code.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class PublicClient
{
    public HttpClient Client { get; }

    public PublicClient(HttpClient httpClient)
    {
        Client = httpClient;
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This code is quite straightforward, we're just accepting a instance of &lt;code&gt;HttpClient&lt;/code&gt; through DI and saving it off to the &lt;code&gt;Client&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;Then in &lt;code&gt;Program.Main&lt;/code&gt; we add the following code.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.Services.AddHttpClient&amp;lt;PublicClient&amp;gt;(client =&amp;gt; client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is going to inject an &lt;code&gt;HttpClient&lt;/code&gt; instance, configured with the base address we've specified, into our &lt;code&gt;PublicClient&lt;/code&gt; class. It will also add our &lt;code&gt;PublicClient&lt;/code&gt; class into the DI container so we can request an instance of it with the preconfigured &lt;code&gt;HttpClient&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can then use it like this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@inject PublicClient PublicClient

...

@code {
    private async Task GetSomethingFromAPI()
    {
        var result = PublicClient.Client.GetFromJsonAsync&amp;lt;Something&amp;gt;("/api/something");
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I think this is a much cleaner way to do things, it's saved us a line of code in our component and it's more obvious at a glance the type of client we are using. Using this approach also allows us to abstract the underlying &lt;code&gt;HttpClient&lt;/code&gt; entirely, if we wish. We can write methods on the &lt;code&gt;PublicClient&lt;/code&gt; so we never expose the &lt;code&gt;HttpClient&lt;/code&gt; to calling code.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class PublicClient
{
    private HttpClient _client

    public PublicClient(HttpClient httpClient)
    {
        _client = httpClient;
    }

    public async Task&amp;lt;SomeThing&amp;gt; GetSomething()
    {
        var result = await _client.GetFromJsonAsync&amp;lt;SomeThing&amp;gt;("/api/something");
        return result;
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&amp;lt;!--kg-card-end: markdown--&amp;gt;&amp;lt;!--kg-card-begin: markdown--&amp;gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@inject PublicClient PublicClient

...

@code {
    private async Task GetSomethingFromAPI()
    {
        var result = PublicClient.GetSomething();
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This code is now really succinct, we've also centralised all our API calling code which should make any future maintenance simpler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this post we've explored a potential issue with unauthenticated users calling unprotected endpoints using the default &lt;code&gt;HttpClient&lt;/code&gt; that comes with the Blazor WebAssembly auth templates. We've investigated Blazors source to understand where this comes from and then we've applied a solution which was to add a second &lt;code&gt;HttpClient&lt;/code&gt; instance.&lt;/p&gt;

&lt;p&gt;Once we had this working we also looked at a different implementation of the solution which made our code a bit simpler and easier to understand, as well as potentially making API calling code easier to maintain in the long run.&lt;/p&gt;

</description>
      <category>blazor</category>
      <category>webdev</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Auto Saving Form Data in Blazor</title>
      <dc:creator>Chris Sainty</dc:creator>
      <pubDate>Tue, 05 May 2020 08:00:00 +0000</pubDate>
      <link>https://dev.to/chrissainty/auto-saving-form-data-in-blazor-4m77</link>
      <guid>https://dev.to/chrissainty/auto-saving-form-data-in-blazor-4m77</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PYVwkEsk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/05/auto-saving-form-data-in-blazor.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PYVwkEsk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/05/auto-saving-form-data-in-blazor.jpg" alt="Auto Saving Form Data in Blazor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I got tagged in a thread on Twitter last week by &lt;a href="https://twitter.com/RockyLhotka"&gt;Mr Rockford Lhotka&lt;/a&gt;. I've embedded the thread below so you can read it for yourself, but essentially he was voicing his frustration at losing data when an error/timeout/server error/etc occur in web applications.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I hate the web. I've hated the web forever. Type in a thoughtful bit of content, click save, get some server/gateway timeout, lose your content. You'd think we've have this solved, but no. 1995-present this is a problem. f-cking web.&lt;/p&gt;

&lt;p&gt;— Rockford Lhotka (@RockyLhotka) &lt;a href="https://twitter.com/RockyLhotka/status/1255347828852953089?ref_src=twsrc%5Etfw"&gt;April 29, 2020&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, this type of situation very much depends on the application and how it's been developed, but, none the less, I agree. There is nothing worse than spending ages filling in a form and then for something to blow up and lose everything you've entered.&lt;/p&gt;

&lt;p&gt;He and &lt;a href="https://twitter.com/DanWahlin"&gt;Dan Wahlin&lt;/a&gt; were discussing the idea of a form auto saving data so it could be recovered if something went wrong with the application. I got tagged by Rockford suggesting it would be a great addition to &lt;a href="https://github.com/Blazored"&gt;Blazored&lt;/a&gt; – Challenge accepted! 😃&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Speaking of which - a good thing for &lt;a href="https://twitter.com/chris_sainty?ref_src=twsrc%5Etfw"&gt;@chris_sainty&lt;/a&gt; to add to his blazord project? 😁😁😁&lt;/p&gt;

&lt;p&gt;— Rockford Lhotka (@RockyLhotka) &lt;a href="https://twitter.com/RockyLhotka/status/1255360086974873606?ref_src=twsrc%5Etfw"&gt;April 29, 2020&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this post, I'm going to show you a solution I've come up with for auto saving and rehydrating form data in Blazor. I'm going to start by outlining the goals and boundaries I set for this project. Then I'm going to tell you about some options I decided not to go with and why I didn't pursue them. Then I'll get into the meat of things and step through the solution I developed. I'll show how I satisfied each goal set out at the start. Then I'll finish by showing you how using the solution compares to the existing &lt;code&gt;EditForm&lt;/code&gt; experience.&lt;/p&gt;

&lt;p&gt;I want to be clear this is by no means a bullet proof, cover all bases solution. It's more an MVP to be built on. I'm hoping to release this as a new package under Blazored after a bit more development and refinement. If you want to help out with that then I've included a link to the new repo at the end of the post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining the Goals
&lt;/h2&gt;

&lt;p&gt;To give myself some focus and boundaries I made a list of four things that needed to be achieved in order for this to be considered useful.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Save data to local storage when it's entered into each form controls&lt;/li&gt;
&lt;li&gt;Rehydrate data from local storage when the user returns to the page&lt;/li&gt;
&lt;li&gt;Clear saved data from local storage when it's successfully submitted by the form&lt;/li&gt;
&lt;li&gt;Try to keep things as close to the current experience with &lt;code&gt;EditForm&lt;/code&gt; as possible for developers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There were also some things that I wanted to rule out for now.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only persist to local storage&lt;/li&gt;
&lt;li&gt;Don't worry about complex forms with nested complex objects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now I had a defined scope for the work, I could start playing around with some ideas and see what I could come up with.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cutting Room Floor
&lt;/h2&gt;

&lt;p&gt;As you would expect, I went though many failed ideas before I settled on a solution I was happy with. I thought it might be interesting to briefly highlight what they were and why I didn't pursue them.&lt;/p&gt;

&lt;h3&gt;
  
  
  First attempt
&lt;/h3&gt;

&lt;p&gt;I started with the idea of creating a new component which could be nested inside an &lt;code&gt;EditForm&lt;/code&gt;, similar to the &lt;code&gt;DataAnnotationValidator&lt;/code&gt;. I quickly got something in-place which used the cascaded &lt;code&gt;EditContext&lt;/code&gt;, provided by &lt;code&gt;EditForm&lt;/code&gt;, to hook into the &lt;code&gt;OnFieldChanged&lt;/code&gt; event. From here I could intercept model updates and persist the model to local storage.&lt;/p&gt;

&lt;p&gt;The problem came when trying to rehydrate the form. Due to where my component sat in the component tree, the UI wasn't updating to show the values in the textboxes. I needed a &lt;code&gt;StateHasChanged&lt;/code&gt; call higher in the tree and I just couldn't get that to work in a nice way.&lt;/p&gt;

&lt;p&gt;I also would need to know when the form had been submitted so I could achieve number 3 on my goals list, clearing the saved values on a successful form post. There was no way I could reliably do that using the &lt;code&gt;EditContext&lt;/code&gt; alone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Second attempt
&lt;/h3&gt;

&lt;p&gt;After some hacking about I came to the conclusion that the best option was going to be a new form component, replacing &lt;code&gt;EditForm&lt;/code&gt;. I wanted to save duplicating all of the code from &lt;code&gt;EditForm&lt;/code&gt; and just inherit from it. I could then add some additional functionality to save and load the form values.&lt;/p&gt;

&lt;p&gt;Unfortunately, that was a short lived hope. I needed access to some members which were private. I got round that with some reflection foo, but the show stopper was needing to add some additional logic in the &lt;code&gt;HandleSubmitAsync&lt;/code&gt; method, there was no way to hack this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In the end, I concluded that I would need to duplicate the &lt;code&gt;EditForm&lt;/code&gt; component and use it as a starting point for my new form component. It wasn't the end of the world, after my experimenting I was happy with the fact I had to change the behaviour of the original component enough that just extending it wasn't going to work.&lt;/p&gt;

&lt;p&gt;With this decision made I then moved on to what became the solution I ended up with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the AutoSaveEditForm Component
&lt;/h2&gt;

&lt;p&gt;The starting point for the new component was the existing &lt;code&gt;EditForm&lt;/code&gt; component produced by the Blazor team. If you want to see this in its unaltered state you can find it &lt;a href="https://github.com/dotnet/aspnetcore/blob/master/src/Components/Web/src/Forms/EditForm.cs"&gt;here&lt;/a&gt;. Let's go through each of the changes I made and why.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integrating with Local Storage
&lt;/h3&gt;

&lt;p&gt;The first thing I did was to add the functionality to persist and retrieve the form to and from local storage. This required injecting &lt;code&gt;IJSRuntime&lt;/code&gt; into the component and then adding the following two methods.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private async void SaveToLocalStorage(object sender, FieldChangedEventArgs args)
{
    var model = Model ?? _fixedEditContext.Model;
    var serializedData = JsonSerializer.Serialize(model);
    await _jsRuntime.InvokeVoidAsync("localStorage.setItem", Id, serializedData);
}

private async Task&amp;lt;object&amp;gt; LoadFromLocalStorage()
{
    var serialisedData = await _jsRuntime.InvokeAsync&amp;lt;string&amp;gt;("localStorage.getItem", Id);
    if (serialisedData == null) return null;
    var modelType = EditContext?.Model.GetType() ?? Model.GetType();

    return JsonSerializer.Deserialize(serialisedData, modelType);
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Both of these methods do exactly what they say on the tin. &lt;code&gt;SaveToLocalStorage&lt;/code&gt; persists the current form model and &lt;code&gt;LoadFromLocalStorage&lt;/code&gt; retrieves the form model.&lt;/p&gt;

&lt;p&gt;In order to identify a particular form, I added an &lt;code&gt;Id&lt;/code&gt; parameter to the component which you can see used in the code above. It's worth pointing out that this is definitely something which will need to be improved before the component could be used in a real app – this method won't be enough to guarantee uniqueness across an application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hooking into Field Changes
&lt;/h3&gt;

&lt;p&gt;With the local storage interfaces in place I moved on to saving the form when fields were updated. This required making some changes to the existing &lt;code&gt;OnParametersSet&lt;/code&gt; method. There's an &lt;code&gt;if&lt;/code&gt; statement at the end of the original method which looks like this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (_fixedEditContext == null || EditContext != null || Model != _fixedEditContext.Model)
{
    _fixedEditContext = EditContext ?? new EditContext(Model);
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I updated it to this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (_fixedEditContext == null || EditContext != null || Model != _fixedEditContext.Model)
{
    _fixedEditContext = EditContext ?? new EditContext(Model);
    _fixedEditContext.OnFieldChanged += SaveToLocalStorage;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I added an extra line which registers a handler for the &lt;code&gt;EditContext&lt;/code&gt;s &lt;code&gt;OnFieldChanged&lt;/code&gt; event. Now, whenever a field on the form model is updated the &lt;code&gt;SaveToLocalStorage&lt;/code&gt; method will be called and the form will be persisted to local storage.&lt;/p&gt;

&lt;p&gt;With the above changes I'd satisfied number 1 on my goals list:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;del&gt;Save data to local storage when it's entered into each form controls&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;Rehydrate data from local storage when the user returns to the page&lt;/li&gt;
&lt;li&gt;Clear saved data from local storage when it's successfully submitted by the form&lt;/li&gt;
&lt;li&gt;Try to keep things as close to the current experience with &lt;code&gt;EditForm&lt;/code&gt; as possible for developers&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Rehydrating the Form Model
&lt;/h3&gt;

&lt;p&gt;I played around with a lot of ideas for this and ended up settling on the use of reflection. This was because I needed to update the specific instance of the model passed in, anything else I tried ultimately ended up overwriting that instance with a new one.&lt;/p&gt;

&lt;p&gt;I came up with the following method which is used to copy the values from the form model retrieved from local storage, to the active form model.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void Copy(object savedFormModel, object currentFormModel)
{
    var savedFormModelProperties = savedFormModel.GetType().GetProperties();
    var currentFormModelProperties = currentFormModel.GetType().GetProperties();

    foreach (var savedFormModelProperty in savedFormModelProperties)
    {
        foreach (var currentFormModelProperty in currentFormModelProperties)
        {
            if (savedFormModelProperty.Name == currentFormModelProperty.Name &amp;amp;&amp;amp; savedFormModelProperty.PropertyType == currentFormModelProperty.PropertyType)
            {
                var childValue = currentFormModelProperty.GetValue(currentFormModel);
                var parentValue = savedFormModelProperty.GetValue(savedFormModel);

                if (childValue == null &amp;amp;&amp;amp; parentValue == null) continue;

                currentFormModelProperty.SetValue(currentFormModel, parentValue);

                var fieldIdentifier = new FieldIdentifier(currentFormModel, currentFormModelProperty.Name);
                _fixedEditContext.NotifyFieldChanged(fieldIdentifier);

                break;
            }
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In a nutshell, this code is looping over each property on the saved form model and then finding that same property on the current form model and transferring the value.&lt;/p&gt;

&lt;p&gt;A key thing to note is the call to &lt;code&gt;_fixedEditContext.NotifyFieldChanged(fieldIdentifier);&lt;/code&gt;. This lets the current edit context know that the value has been updated and triggers all the right events, a key one being any validation for that field.&lt;/p&gt;

&lt;p&gt;With that method in placed I overrode the &lt;code&gt;OnAfterRender&lt;/code&gt; lifecycle method and added the following code.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        var savedModel = await LoadFromLocalStorage();

        if (Model is object &amp;amp;&amp;amp; savedModel is object)
        {
            Copy(savedModel, Model);
            StateHasChanged();
        }
        else if (savedModel is object)
        {
            Copy(savedModel, _fixedEditContext.Model);
            StateHasChanged();
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When the component first renders, this code will check local storage for an existing saved form model. If one is found then it will use the &lt;code&gt;Copy&lt;/code&gt; method we just looked at to copy values from the saved form model to the current one. Once this has been done it will call &lt;code&gt;StateHasChanged&lt;/code&gt;, this is important as it will refresh the UI and show the newly copied values in the form controls.&lt;/p&gt;

&lt;p&gt;This was number 2 ticked off the list of goals, form values were now being reloaded from local storage when a user revisited a page.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;del&gt;Save data to local storage when it's entered into each form controls&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Rehydrate data from local storage when the user returns to the page&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;Clear saved data from local storage when it's successfully submitted by the form&lt;/li&gt;
&lt;li&gt;Try to keep things as close to the current experience with &lt;code&gt;EditForm&lt;/code&gt; as possible for developers&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Clearing saved form data on a successful submit
&lt;/h3&gt;

&lt;p&gt;This one took me a bit of time to get working and for a very specific reason. If I wanted to honour number 4 on my goals list, keep things close to the current developer experience, I wanted to allow developers to still use the same form events &lt;code&gt;OnSubmit&lt;/code&gt;, &lt;code&gt;OnValidSubmit&lt;/code&gt; and &lt;code&gt;OnInvalidSubmit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The original method which handles the submit events is called &lt;code&gt;HandleSubmitAsync&lt;/code&gt; and looks like this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private async Task HandleSubmitAsync()
{
    if (OnSubmit.HasDelegate)
    {
        await OnSubmit.InvokeAsync(_fixedEditContext);
    }
    else
    {
        if (isValid &amp;amp;&amp;amp; OnValidSubmit.HasDelegate)
        {
            await OnValidSubmit.InvokeAsync(_fixedEditContext);
        }

        if (!isValid &amp;amp;&amp;amp; OnInvalidSubmit.HasDelegate)
        {
            await OnInvalidSubmit.InvokeAsync(_fixedEditContext);
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Keeping &lt;code&gt;OnInvalidSubmit&lt;/code&gt; doesn't require any action in terms of the saved form model. For &lt;code&gt;OnValidSubmit&lt;/code&gt; I only had to make the following change to clear local storage after the &lt;code&gt;OnValidSubmit&lt;/code&gt; event has been invoked.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (isValid &amp;amp;&amp;amp; OnValidSubmit.HasDelegate)
{
    await OnValidSubmit.InvokeAsync(_fixedEditContext);

    // Clear saved form model from local storage
    await _jsRuntime.InvokeVoidAsync("localStorage.removeItem", Id);
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The headache came when trying to keep the &lt;code&gt;OnSubmit&lt;/code&gt; event. This event requires the developer to handle the validation of the form manually and then submit it. With the existing design, there is no way for me to know if the form had been submitted and that the saved form model could be removed.&lt;/p&gt;

&lt;p&gt;After some back and fourth I came up with the following design which does require some extra steps from the consumer but I think is worth the trade off.&lt;/p&gt;

&lt;p&gt;The original &lt;code&gt;OnSubmit&lt;/code&gt; event is typed as an &lt;code&gt;EventCallback&amp;lt;EditContext&amp;gt;&lt;/code&gt; as follows.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Parameter] public EventCallback&amp;lt;EditContext&amp;gt; OnSubmit { get; set; }

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I updated the definition of the &lt;code&gt;OnSubmit&lt;/code&gt; parameter to this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Parameter] public Func&amp;lt;EditContext, Task&amp;lt;bool&amp;gt;&amp;gt; OnSubmit { get; set; }

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I'm now requiring the developer to register a method which returns a &lt;code&gt;bool&lt;/code&gt; to let me know if the form was submitted successfully or not. Making this change did break a check performed in &lt;code&gt;OnParametersSet&lt;/code&gt;.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (OnSubmit.HasDelegate &amp;amp;&amp;amp; (OnValidSubmit.HasDelegate || OnInvalidSubmit.HasDelegate))

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This just required a simple update.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (OnSubmit is object &amp;amp;&amp;amp; (OnValidSubmit.HasDelegate || OnInvalidSubmit.HasDelegate))

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once that was fixed I could then update the code in &lt;code&gt;HandleSubmitAsync&lt;/code&gt; to this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (OnSubmit is object)
{
    var submitSuccess = await OnSubmit.Invoke(_fixedEditContext);
    if (submitSuccess)
    {
        await _jsRuntime.InvokeVoidAsync("localStorage.removeItem", Id);
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I could now await the bool value from the consumer code and if it's &lt;code&gt;true&lt;/code&gt; the saved form model is removed form local storage. The complete updated &lt;code&gt;HandleSubmitAsync&lt;/code&gt; method looks like this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private async Task HandleSubmitAsync()
{
    if (OnSubmit is object)
    {
        var submitSuccess = await OnSubmit.Invoke();
        if (submitSuccess)
        {
            await _jsRuntime.InvokeVoidAsync("localStorage.removeItem", Id);
        }
    }
    else
    {
        if (isValid &amp;amp;&amp;amp; OnValidSubmit.HasDelegate)
        {
            await OnValidSubmit.InvokeAsync(_fixedEditContext);
            await _jsRuntime.InvokeVoidAsync("localStorage.removeItem", Id);
        }

        if (!isValid &amp;amp;&amp;amp; OnInvalidSubmit.HasDelegate)
        {
            await OnInvalidSubmit.InvokeAsync(_fixedEditContext);
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;At this point I was happy to tick off number 3 on my goals list.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;del&gt;Save data to local storage when it's entered into each form controls&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Rehydrate data from local storage when the user returns to the page&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Clear saved data from local storage when it's successfully submitted by the form&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;Try to keep things as close to the current experience with &lt;code&gt;EditForm&lt;/code&gt; as possible for developers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The only remaining goal was number 4, and the only way to tick that off is to check a few things from the consuming developers point of view and see how it compares to the original &lt;code&gt;EditForm&lt;/code&gt; component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the AutoSaveEditForm Component
&lt;/h2&gt;

&lt;p&gt;Let's look at a simple example of form usage first. We'll use a model which contains two fields, &lt;code&gt;FirstName&lt;/code&gt; and &lt;code&gt;LastName&lt;/code&gt;. To make sure validation is working we'll also make the &lt;code&gt;LastName&lt;/code&gt; required.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class MyFormModel
{
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;First we'll look at using &lt;code&gt;EditForm&lt;/code&gt; and its &lt;code&gt;OnValidSubmit&lt;/code&gt; event. The code is as follows.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;EditForm Model="myFormModel" OnValidSubmit="HandleValidSubmit"&amp;gt;
    &amp;lt;DataAnnotationsValidator /&amp;gt;

    &amp;lt;InputText @bind-Value="myFormModel.FirstName" /&amp;gt;
    &amp;lt;InputText @bind-Value="myFormModel.LastName" /&amp;gt;

    &amp;lt;button type="submit"&amp;gt;Submit&amp;lt;/button&amp;gt;
&amp;lt;/EditForm&amp;gt;

@code {
    private MyFormModel myFormModel = new MyFormModel();

    private void HandleValidSubmit()
    {
        Console.WriteLine($"Form Submitted For: {myFormModel.FirstName} {myFormModel.LastName}");
        myFormModel = new MyFormModel();
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So how does this compare with &lt;code&gt;AutoSaveEditForm&lt;/code&gt;?&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;AutoSaveEditForm Id="form-one" Model="myFormModel" OnValidSubmit="HandleValidSubmit"&amp;gt;
    &amp;lt;DataAnnotationsValidator /&amp;gt;

    &amp;lt;InputText @bind-Value="myFormModel.FirstName" /&amp;gt;
    &amp;lt;InputText @bind-Value="myFormModel.LastName" /&amp;gt;

    &amp;lt;button type="submit"&amp;gt;Submit&amp;lt;/button&amp;gt;
&amp;lt;/AutoSaveEditForm&amp;gt;

@code {
    private MyFormModel myFormModel = new MyFormModel();

    private void HandleValidSubmit()
    {
        Console.WriteLine($"Form Submitted For: {myFormModel.FirstName} {myFormModel.LastName}");
        myFormModel = new MyFormModel();
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The only changes needed were the name of the component and the addition of the &lt;code&gt;Id&lt;/code&gt; parameter. That's pretty cool, really minimal changes for existing developers. But what about a slightly more complex example?&lt;/p&gt;

&lt;p&gt;Let's look at the scenario where the developer is using the &lt;code&gt;OnSubmit&lt;/code&gt; event and manually validating. This is what the code looks like with the &lt;code&gt;EditForm&lt;/code&gt; component.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;EditForm Model="myFormModel" OnSubmit="HandleSubmit"&amp;gt;
    &amp;lt;DataAnnotationsValidator /&amp;gt;

    &amp;lt;InputText @bind-Value="myFormModel.FirstName" /&amp;gt;
    &amp;lt;InputText @bind-Value="myFormModel.LastName" /&amp;gt;

    &amp;lt;button type="submit"&amp;gt;Submit&amp;lt;/button&amp;gt;
&amp;lt;/EditForm&amp;gt;

@code {
    private MyFormModel myFormModel = new MyFormModel();

    private void HandleSubmit(EditContext editContext)
    {
        var isValid = editContext.Validate();

        if (isValid)
        {
            Console.WriteLine($"Form Submitted For: {myFormModel.FirstName} {myFormModel.LastName}");
            myFormModel = new MyFormModel();
        }
        else
        {
            Console.WriteLine($"Form Invalid");
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here's the code with auto save.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;AutoSaveEditForm Id="form-one" Model="myFormModel" OnSubmit="HandleSubmit"&amp;gt;
    &amp;lt;DataAnnotationsValidator /&amp;gt;

    &amp;lt;InputText @bind-Value="myFormModel.FirstName" /&amp;gt;
    &amp;lt;InputText @bind-Value="myFormModel.LastName" /&amp;gt;

    &amp;lt;button type="submit"&amp;gt;Submit&amp;lt;/button&amp;gt;
&amp;lt;/AutoSaveEditForm&amp;gt;

@code {
    private MyFormModel myFormModel = new MyFormModel();

    private async Task&amp;lt;bool&amp;gt; HandleSubmit(EditContext editContext)
    {
        var isValid = editContext.Validate();

        if (isValid)
        {
            Console.WriteLine($"Form Submitted For: {myFormModel.FirstName} {myFormModel.LastName}");
            myFormModel = new MyFormModel();

            return true;
        }
        else
        {
            Console.WriteLine($"Form Invalid");
            StateHasChanged();
            return false;
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I think you'll agree, that's not bad and sticks pretty close to the original developer experience.&lt;/p&gt;

&lt;p&gt;While I appreciate these are simple examples, I'm happy to take that as a win and tick off number 4 on the goals list.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;del&gt;Save data to local storage when it's entered into each form controls&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Rehydrate data from local storage when the user returns to the page&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Clear saved data from local storage when it's successfully submitted by the form&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Try to keep things as close to the current experience with &lt;code&gt;EditForm&lt;/code&gt; as possible for developers&lt;/del&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I've created a gif to show what this looks like from the users perspective when using the component in an application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HW3cxR6L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://chrissainty.com/content/images/2020/05/auto-save-in-blazor.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HW3cxR6L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://chrissainty.com/content/images/2020/05/auto-save-in-blazor.gif" alt="Auto Saving Form Data in Blazor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I just want to reiterate again, this is &lt;strong&gt;not&lt;/strong&gt; a fool-proof and complete solution. It's just a starting point. I do think it's really awesome that all this has been possible using just C# code. As you may have noticed, I've not had to write any JavaScript to achieve this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blazored AutoSaveEditForm
&lt;/h2&gt;

&lt;p&gt;As I mentioned at the start, this is the starting point for a new component I'm adding to &lt;a href="https://github.com/Blazored"&gt;Blazored&lt;/a&gt; – you can find the &lt;a href="https://github.com/Blazored/AutoSaveEditForm"&gt;repo here&lt;/a&gt;. It contains the complete code from this post and any suggestions are welcome, just open an issue. Also if anyone wants to help out with getting the component to a state where it's ready for public use, please let me know.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;If you've made it this far, well done! For those looking for the complete source code I haven't published this yet as what you've just read about is the starting point for a new component which is going to be added to Blazored very soon.&lt;/p&gt;

&lt;p&gt;In this post I've walked you though my design for a new form component which will persist form values to local storage until the form is submitted successfully. I started by showing why I was attempting this and the goals and boundaries for this work.&lt;/p&gt;

&lt;p&gt;Then I talked about some of the brain storming I did and some other options I decided not to go with for the end design. Before taking you through the design for the end component which is based on the original &lt;code&gt;EditForm&lt;/code&gt; component produced by the Blazor team.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>blazor</category>
      <category>webdev</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Copy to Clipboard in Blazor</title>
      <dc:creator>Chris Sainty</dc:creator>
      <pubDate>Wed, 29 Apr 2020 08:38:48 +0000</pubDate>
      <link>https://dev.to/chrissainty/copy-to-clipboard-in-blazor-3di2</link>
      <guid>https://dev.to/chrissainty/copy-to-clipboard-in-blazor-3di2</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WukvY6xq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/copy-to-clipboard-in-blazor.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WukvY6xq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/copy-to-clipboard-in-blazor.jpg" alt="Copy to Clipboard in Blazor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently I was creating a new repo on GitHub, a pretty common action for most of us now-a-days. When I noticed a feature which I use everytime but had never given much thought to, the copy to clipboard button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V2LUJS6p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/github-copytoclipboard.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V2LUJS6p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/github-copytoclipboard.jpg" alt="Copy to Clipboard in Blazor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a really useful feature, as I said a second ago, I literally use it everytime. Another great example of this can be found on the &lt;a href="https://getbootstrap.com"&gt;Bootstrap site&lt;/a&gt;. Each code example has a copy button in the top right corner allowing developers to copy the sample code straight to their clipboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PPs2XL0k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/bootstrap-copytoclipboard.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PPs2XL0k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/bootstrap-copytoclipboard.jpg" alt="Copy to Clipboard in Blazor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I thought this would be a cool little feature to be able to use in Blazor applications so thought I would do a bit of investigation and see how it could be replicated.&lt;/p&gt;

&lt;p&gt;In this post I’m going to show you how to create a simple copy to clipboard feature for Blazor apps. We're going to start by looking at the available APIs we can use for this functionality. From there we are going to create two solutions, one for short amounts of text, replicating the GitHub example above. The other for larger amounts of text, replicating the functionality from the Bootstrap docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the API
&lt;/h2&gt;

&lt;p&gt;The first thing to understand is that we can't create the feature using C# code alone, we're going to have to use some JavaScript interop to achieve our goal. There are two API options available to us, &lt;code&gt;Document.execCommand&lt;/code&gt; and &lt;code&gt;Clipboard&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Document.execCommand
&lt;/h3&gt;

&lt;p&gt;Historically, clipboard operations have been achieved using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand"&gt;&lt;code&gt;execCommand&lt;/code&gt;&lt;/a&gt;. A quick google of &lt;em&gt;"copy to clipboard in JavaScript"&lt;/em&gt; will bring up numerous examples using this API. &lt;code&gt;execCommand&lt;/code&gt; is also well supported across the different browsers, a quick check on &lt;a href="https://caniuse.com/#search=execcommand"&gt;caniuse.com&lt;/a&gt; shows lots of green (95.63%).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lqtlgsnQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/caniuse-execcommand.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lqtlgsnQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/caniuse-execcommand.jpg" alt="Copy to Clipboard in Blazor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, there is a rather large issue with this API. It's been marked &lt;em&gt;obsolete&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dlg374NX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/execcommand-obsolite.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dlg374NX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/execcommand-obsolite.jpg" alt="Copy to Clipboard in Blazor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The good news is there's a new API which supersedes it called the Clipboard API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clipboard API
&lt;/h3&gt;

&lt;p&gt;The new &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API"&gt;Clipboard API&lt;/a&gt; has the ability to read and write to the clipboard both syncronously and asyncronously, as well as integrating with the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API"&gt;Permissions API&lt;/a&gt; to ensure the user has given permission to do so.&lt;/p&gt;

&lt;p&gt;The API breaks down into 2 interfaces, &lt;code&gt;Clipboard&lt;/code&gt; and &lt;code&gt;ClipboardEvent&lt;/code&gt;. The &lt;code&gt;ClipboardEvent&lt;/code&gt; interface gives us access to information about the modification of the clipboard by events such as cut, copy and paste. It's good to know this is here but the more intestesting stuff is in the &lt;code&gt;Clipboard&lt;/code&gt; interface.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Clipboard&lt;/code&gt; interface provides us the functions to interact with the clipboard in our applications and contains the following 4 functions (from the MDN docs):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/read"&gt;&lt;code&gt;read()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;Requests arbitrary data (such as images) from the clipboard, returning a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise"&gt;&lt;code&gt;Promise&lt;/code&gt;&lt;/a&gt;. When the data has been retrieved, the promise is resolved with a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer"&gt;&lt;code&gt;DataTransfer&lt;/code&gt;&lt;/a&gt; object that provides the data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/readText"&gt;&lt;code&gt;readText()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;Requests text from the system clipboard; returns a &lt;code&gt;Promise&lt;/code&gt; which is resolved with a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMString"&gt;&lt;code&gt;DOMString&lt;/code&gt;&lt;/a&gt; containing the clipboard's text once it's available.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/write"&gt;&lt;code&gt;write()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;Writes arbitrary data to the system clipboard. This asynchronous operation signals that it's finished by resolving the returned &lt;code&gt;Promise&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText"&gt;&lt;code&gt;writeText()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;Writes text to the system clipboard, returning a &lt;code&gt;Promise&lt;/code&gt; which is resolved once the text is fully copied into the clipboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The adoption of this new API isn't anywhere near as widespread as the old &lt;code&gt;execCommand&lt;/code&gt;. The function we're interested in is &lt;code&gt;writeText&lt;/code&gt; has 71.11% adoption according to caniuse.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GxIR6_56--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/caniuse-clipboard-writetext.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GxIR6_56--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/caniuse-clipboard-writetext.jpg" alt="Copy to Clipboard in Blazor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, the browsers that don't support this also don't support Blazor so that makes thing simple. Based on all the information I decided to go with the new clipboard API for this functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution 1: Replicating GitHubs copy to clipboard
&lt;/h2&gt;

&lt;p&gt;In this first solution we're going to replicate the funcationality from GitHub. This is ideal for any small, single line amounts of text you want to allow users to copy to their clipboards.&lt;/p&gt;

&lt;p&gt;First create a component call &lt;code&gt;CopyToClipboard&lt;/code&gt; with the following code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I'm doing this using the standard Blazor project template which has Bootstrap included. So for styling, I'm just using classes from that and some inline styles where needed.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@inject IJSRuntime

&amp;lt;div class="form-inline"&amp;gt;
    &amp;lt;input class="form-control" readonly type="text" value="@Text" /&amp;gt;
    &amp;lt;button type="button" class="btn btn-primary" @onclick="CopyTextToClipboard"&amp;gt;Copy&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;

@code {    
    [Parameter] public string Text { get; set; }

    private async Task CopyTextToClipboard()
    {
        await JSRuntime.InvokeVoidAsync("clipboardCopy.copyText", Text);
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The component takes in the text which can be copied by the user via the &lt;code&gt;Text&lt;/code&gt; parameter. When the user click on the &lt;code&gt;button&lt;/code&gt; the &lt;code&gt;CopyTextToClipboard&lt;/code&gt; is invoked which calls the following JavaScript.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;window.clipboardCopy = {
    copyText: function(text) {
        navigator.clipboard.writeText(text).then(function () {
            alert("Copied to clipboard!");
        })
        .catch(function (error) {
            alert(error);
        });
    }
};

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The above function calls &lt;code&gt;writeText&lt;/code&gt; to write the text provided from the &lt;code&gt;CopyToClipboard&lt;/code&gt; component to the users clipboard.&lt;/p&gt;

&lt;p&gt;We can use the component like this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;CopyToClipboard Text="Copy this text" /&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Which will produce the following output.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I3oCjgOk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/blazor-github-copytoclipboard-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I3oCjgOk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/blazor-github-copytoclipboard-1.jpg" alt="Copy to Clipboard in Blazor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution 2: Replicating Bootstraps copy to clipboard
&lt;/h2&gt;

&lt;p&gt;This time we're going to replicate the functionality from Bootstrap docs. This is great for copying larger amounts of text. Here is the updated code for the &lt;code&gt;CopyToClipboard&lt;/code&gt; component.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="position-relative" style="background-color: #f5f5f5"&amp;gt;
    &amp;lt;pre&amp;gt;
    &amp;lt;code @ref="_codeElement"&amp;gt;
            @ChildContent
        &amp;lt;/code&amp;gt;
    &amp;lt;/pre&amp;gt;
    &amp;lt;div style="position:absolute; top: 10px; right: 10px;"&amp;gt;
        &amp;lt;button type="button" class="btn btn-primary" @onclick="CopyTextToClipboard"&amp;gt;Copy&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

@code {

    private ElementReference _codeElement;

    [Parameter] public RenderFragment ChildContent { get; set; }

    private async Task CopyTextToClipboard()
    {
        await JSRuntime.InvokeVoidAsync("clipboardCopy.copyText", _codeElement);
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This time we're taking in child content defined by the components consumer and rendering it inside a &lt;code&gt;code&lt;/code&gt; tag. We're capturing a reference to that element using Blazors &lt;code&gt;@ref&lt;/code&gt; directive and passing that to JS when the copy button is clicked.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;window.clipboardCopy = {
    copyText: function (codeElement) {
        navigator.clipboard.writeText(codeElement.textContent).then(function () {
            alert("Copied to clipboard!");
        })
        .catch(function (error) {
            alert(error);
        });
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The JavaScript code is largly the same as before. The only difference is we're receiving an HTML element instead of a text string. When we call &lt;code&gt;writeText&lt;/code&gt; we're now passing in the text inside the &lt;code&gt;code&lt;/code&gt; element using the &lt;code&gt;textContent&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;We can use component like this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;CopyToClipboard&amp;gt;
    @("&amp;lt;div class=\"clipboard-copy\"&amp;gt;")
        @("&amp;lt;button type=\"button\" class=\"btn btn-primary\"&amp;gt;Copy&amp;lt;/button&amp;gt;")
    @("&amp;lt;/div&amp;gt;")
&amp;lt;/CopyToClipboard&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Which will produce the following output.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vW4yBajU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/blazor-bootstrap-copytoclipboard.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vW4yBajU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/blazor-bootstrap-copytoclipboard.jpg" alt="Copy to Clipboard in Blazor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this post I've show a couple of solutions for copying text to the users clipboard in Blazor. We started off by understanding the two API's available in JavaScript for interacting with the clipboard, &lt;code&gt;execCommand&lt;/code&gt; and the &lt;code&gt;Clipboard&lt;/code&gt; API. We concluded that using the new Clipboard API was a better choice due to the &lt;code&gt;execCommand&lt;/code&gt; API being marked obsolete.&lt;/p&gt;

&lt;p&gt;We then looked at two solutions for implementing copy to clipboard functionality. The first allowed short string to be copied to the users clipboard via a simple component with a button which invoked a call into JavaScript. The second method showed how to copy larger volumes of text by passing an &lt;code&gt;ElementReference&lt;/code&gt; to JavaScript and accessing its &lt;code&gt;textContent&lt;/code&gt; property to retrieve the text before copying it to the clipboard.&lt;/p&gt;

</description>
      <category>blazor</category>
      <category>csharp</category>
      <category>dotnet</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Mobile Blazor Bindings - Navigation and Xamarin Essentials</title>
      <dc:creator>Chris Sainty</dc:creator>
      <pubDate>Tue, 21 Apr 2020 08:00:00 +0000</pubDate>
      <link>https://dev.to/chrissainty/mobile-blazor-bindings-navigation-and-xamarin-essentials-40p9</link>
      <guid>https://dev.to/chrissainty/mobile-blazor-bindings-navigation-and-xamarin-essentials-40p9</guid>
      <description>&lt;h2&gt;
  
  
  Mobile Blazor Bindings for Web Developers Series
&lt;/h2&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FnWY4BoS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/mobile-blazor-bindings-navigation-and-xamarin-essentials.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FnWY4BoS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/mobile-blazor-bindings-navigation-and-xamarin-essentials.jpg" alt="Mobile Blazor Bindings - Navigation and Xamarin Essentials"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 1&lt;/strong&gt; - &lt;a href="https://chrissainty.com/getting-started-with-mobile-blazor-bindings"&gt;Mobile Blazor Bindings - Getting Started&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Part 2&lt;/strong&gt; - &lt;a href="https://chrissainty.com/mobile-blazor-bindings-layout-and-styling"&gt;Mobile Blazor Bindings - Layout and Styling&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Part 3&lt;/strong&gt; - &lt;a href="https://dev.to/chrissainty/mobile-blazor-bindings-state-management-and-data-hj0"&gt;Mobile Blazor Bindings - State and Data&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Part 4&lt;/strong&gt; - Mobile Blazor Bindings - Navigation and Xamarin Essentials &lt;em&gt;(this post)&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;We've come to the final post in this series on Mobile Blazor Bindings (MBB). In part 3, we learned about different ways to manage the state of our MBB applications. From simple state held in components to a central state container. We then looked at data, and how we could persist data locally using the SQLite database, as well as back to an API using &lt;code&gt;HttpClient&lt;/code&gt;. Finally, we applied what we'd learned to our Budget Tracker app.&lt;/p&gt;

&lt;p&gt;In this post, we're going to talk about navigation in MBB. We're also going to take a look at Xamarin Essentials, a collection of cross platform operating system and platform APIs we can use from C# to do some cool stuff in our MBB applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Navigation
&lt;/h2&gt;

&lt;p&gt;Coming from the web, we're used to being able to navigate between pages in our apps using URLs. For example, &lt;a href="http://www.mysite.com/about"&gt;www.mysite.com/about&lt;/a&gt; would take us to the about page. And generally speaking, users are free to navigate between pages in any order they choose.&lt;/p&gt;

&lt;p&gt;Mobile apps tend to use a stack based navigation system where every time the user navigates to a new page it's added to the top of a stack. They can then move around the app in a linear fashion by tapping on new pages to go forwards and using the devices back button or a swipe gesture to move backwards.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v_n5E6i2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/stack-navigation-pushing.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v_n5E6i2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/stack-navigation-pushing.png" alt="Mobile Blazor Bindings - Navigation and Xamarin Essentials"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ww86XvmI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/stack-navigation-popping.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ww86XvmI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/stack-navigation-popping.png" alt="Mobile Blazor Bindings - Navigation and Xamarin Essentials"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are different page types, such as &lt;a href="https://docs.microsoft.com/en-gb/xamarin/xamarin-forms/app-fundamentals/navigation/master-detail-page"&gt;&lt;em&gt;MasterDetailPage&lt;/em&gt;&lt;/a&gt;and &lt;em&gt;&lt;a href="https://docs.microsoft.com/en-gb/xamarin/xamarin-forms/app-fundamentals/navigation/tabbed-page"&gt;TabbedPage&lt;/a&gt;,&lt;/em&gt; which give the feeling of a more free movement. But essentially you are just moving around within a defined set of sub pages.&lt;/p&gt;

&lt;p&gt;At the time of writing, there is no formal way to navigate between pages in MBB – This infrastructure isn't in place yet. However, there is a sample application in the MBB repo called &lt;a href="https://github.com/xamarin/MobileBlazorBindings/tree/3c8dd676fc6e7882b4fcdd2ae6f1b97162570607/samples/MobileBlazorBindingsXaminals"&gt;Xaminals&lt;/a&gt;. This does demonstrate a way of navigating using multiple pages using something called &lt;a href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/"&gt;Shell navigation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Shell navigation is a URI-based navigation system for Xamarin applications. This is great for us developers coming from a web background as it naturally fits with the paradigms we're used to working with. It also uses concepts like routes which fit well with Blazors web based hosting models.&lt;/p&gt;

&lt;p&gt;However, I did some experimenting with this technique but I just couldn't get things to do what I wanted. The biggest hurdle which I couldn't overcome was setting a starting page for the application. Also as Shell navigation isn't an official way to navigate, you can't get parameters populated from the "route" as you would in web based Blazor apps. However, you could overcome this by pulling any required state from a central state container like we talked about in &lt;a href="https://dev.to/chrissainty/mobile-blazor-bindings-state-management-and-data-hj0"&gt;part 3&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I think for me, navigation is just a little to alpha right now so I'm going to wait and see what comes down the line. Luckily, our Budget Tracker app doesn't need multiple pages so it won't impact us in any way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Xamarin Essentials
&lt;/h2&gt;

&lt;p&gt;So far, we've talked a lot about the fundamentals required to start building native mobile apps with MBB. But what about doing some more advanced/cool things like Geolocation or making the device vibrate. That's where &lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/"&gt;Xamarin Essentials&lt;/a&gt; comes in.&lt;/p&gt;

&lt;p&gt;Xamarin Essentials offers a set of operating system and platform APIs which we can use from C#. Those of you who've been following this series will know that we've briefly mentioned Xamarin Essentials in &lt;a href="https://dev.to/chrissainty/mobile-blazor-bindings-state-management-and-data-hj0"&gt;part 3&lt;/a&gt; where we talked about using the Connectivity feature to decide whether to save data locally or to an API. But that was just the tip of the iceberg, here's the full list of features available from Xamarin Essentials right now.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/accelerometer?context=xamarin/xamarin-forms"&gt;Accelerometer&lt;/a&gt; – Retrieve acceleration data of the device in three dimensional space.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/app-information?context=xamarin/xamarin-forms"&gt;App Information&lt;/a&gt; – Find out information about the application.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/app-theme?context=xamarin/xamarin-forms"&gt;App Theme&lt;/a&gt; – Detect the current theme requested for the application.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/barometer?context=xamarin/xamarin-forms"&gt;Barometer&lt;/a&gt; – Monitor the barometer for pressure changes.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/battery?context=xamarin/xamarin-forms"&gt;Battery&lt;/a&gt; – Easily detect battery level, source, and state.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/clipboard?context=xamarin/xamarin-forms"&gt;Clipboard&lt;/a&gt; – Quickly and easily set or read text on the clipboard.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/color-converters?context=xamarin/xamarin-forms"&gt;Color Converters&lt;/a&gt; – Helper methods for System.Drawing.Color.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/compass?context=xamarin/xamarin-forms"&gt;Compass&lt;/a&gt; – Monitor compass for changes.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/connectivity?context=xamarin/xamarin-forms"&gt;Connectivity&lt;/a&gt; – Check connectivity state and detect changes.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/detect-shake?context=xamarin/xamarin-forms"&gt;Detect Shake&lt;/a&gt; – Detect a shake movement of the device.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/device-display?context=xamarin/xamarin-forms"&gt;Device Display Information&lt;/a&gt; – Get the device's screen metrics and orientation.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/device-information?context=xamarin/xamarin-forms"&gt;Device Information&lt;/a&gt; – Find out about the device with ease.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/email?context=xamarin/xamarin-forms"&gt;Email&lt;/a&gt; – Easily send email messages.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/file-system-helpers?context=xamarin/xamarin-forms"&gt;File System Helpers&lt;/a&gt; – Easily save files to app data.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/flashlight?context=xamarin/xamarin-forms"&gt;Flashlight&lt;/a&gt; – A simple way to turn the flashlight on/off.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/geocoding?context=xamarin/xamarin-forms"&gt;Geocoding&lt;/a&gt; – Geocode and reverse geocode addresses and coordinates.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/geolocation?context=xamarin/xamarin-forms"&gt;Geolocation&lt;/a&gt; – Retrieve the device's GPS location.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/gyroscope?context=xamarin/xamarin-forms"&gt;Gyroscope&lt;/a&gt; – Track rotation around the device's three primary axes.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/launcher?context=xamarin/xamarin-forms"&gt;Launcher&lt;/a&gt; – Enables an application to open a URI by the system.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/magnetometer?context=xamarin/xamarin-forms"&gt;Magnetometer&lt;/a&gt; – Detect device's orientation relative to Earth's magnetic field.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/main-thread?content=xamarin/xamarin-forms"&gt;MainThread&lt;/a&gt; – Run code on the application's main thread.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/maps?content=xamarin/xamarin-forms"&gt;Maps&lt;/a&gt; – Open the maps application to a specific location.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/open-browser?context=xamarin/xamarin-forms"&gt;Open Browser&lt;/a&gt; – Quickly and easily open a browser to a specific website.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/orientation-sensor?context=xamarin/xamarin-forms"&gt;Orientation Sensor&lt;/a&gt; – Retrieve the orientation of the device in three dimensional space.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/permissions?context=xamarin/xamarin-forms"&gt;Permissions&lt;/a&gt; – Check and request permissions from users.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/phone-dialer?context=xamarin/xamarin-forms"&gt;Phone Dialer&lt;/a&gt; – Open the phone dialer.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/platform-extensions?context=xamarin/xamarin-forms"&gt;Platform Extensions&lt;/a&gt; – Helper methods for converting Rect, Size, and Point.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/preferences?context=xamarin/xamarin-forms"&gt;Preferences&lt;/a&gt; – Quickly and easily add persistent preferences.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/secure-storage?context=xamarin/xamarin-forms"&gt;Secure Storage&lt;/a&gt; – Securely store data.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/share?context=xamarin/xamarin-forms"&gt;Share&lt;/a&gt; – Send text and website uris to other apps.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/sms?context=xamarin/xamarin-forms"&gt;SMS&lt;/a&gt; – Create an SMS message for sending.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/text-to-speech?context=xamarin/xamarin-forms"&gt;Text-to-Speech&lt;/a&gt; – Vocalize text on the device.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/unit-converters?context=xamarin/xamarin-forms"&gt;Unit Converters&lt;/a&gt; – Helper methods to convert units.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/version-tracking?context=xamarin/xamarin-forms"&gt;Version Tracking&lt;/a&gt; – Track the applications version and build numbers.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/vibrate?context=xamarin/xamarin-forms"&gt;Vibrate&lt;/a&gt; – Make the device vibrate.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/xamarin/essentials/web-authenticator?context=xamarin/xamarin-forms"&gt;Web Authenticator&lt;/a&gt; - Start web authentication flows and listen for a callback.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I think you'll agree there is a lot of cool stuff there to explore. I'm not going to talk about each item here, I'll leave it to you to explore the particular features you're interested in. I've included a link with each feature to it's docs page to get you started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Dark Mode to Budget Tracker
&lt;/h2&gt;

&lt;p&gt;To finished things off we're going to use one of the features from Xamarin Essentials to add a dark mode options to Budget Tracker. I mean, let's face it, it's not a real app unless it has a dark mode! 😆&lt;/p&gt;

&lt;p&gt;We're going to use the App Theme feature which will allow us to ask for the current theme set on the OS. This will return one of three options to us, &lt;code&gt;Dark&lt;/code&gt;, &lt;code&gt;Light&lt;/code&gt; or &lt;code&gt;Unspecified&lt;/code&gt;. Based on this, we can load a different style sheet for either light or dark mode. It's worth pointing out that this feature only works on the newer versions of Android and iOS, here are the specifics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Android 10+ (API level 29+) - Older versions return &lt;code&gt;Light&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;iOS 13+ - Older versions return &lt;code&gt;Unspecified&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Creating a Dark Theme
&lt;/h3&gt;

&lt;p&gt;To start we'll rename the existing stylesheet to &lt;code&gt;BudgetTrackerLight.css&lt;/code&gt; and then make a copy of it and call that &lt;code&gt;BudgetTrackerDark.css&lt;/code&gt;. In here we'll update the various styles with the new dark colour scheme.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;entry {
    font-size: 30;
    color: #F7FAFC;
    background-color: #718096;
}

frame {
    border-radius: 10;
    background-color: #4A5568;
}

label {
    color: #CBD5E0;
    -xf-horizontal-text-alignment: center;
}

button {
    background-color: #718096;
    color: #E2E8F0;
}

.textSmall {
    font-size: 12;
}

.homeContainer {
    padding: 10;
    background-color: #1A202C;
}

.balanceContainer {
    margin: 0 0 10 0;
    -xf-spacing: 0;
}

    .balanceContainer &amp;gt; .currentBalance {
        font-size: 30;
        color: #F7FAFC;
        -xf-vertical-text-alignment: center;
        -xf-horizontal-text-alignment: center;
    }

.budgetContainer {
    -xf-spacing: 0;
}

    .budgetContainer &amp;gt; .currentBudget {
        font-size: 20;
        color: #48BB78;
        -xf-vertical-text-alignment: center;
        -xf-horizontal-text-alignment: center;
    }

.expensesContainer {
    -xf-spacing: 0;
}

    .expensesContainer &amp;gt; .currentExpenses {
        font-size: 20;
        color: #E53E3E;
        -xf-vertical-text-alignment: center;
        -xf-horizontal-text-alignment: center;
    }

.currencySymbol {
    color: #718096;
    font-size: 30;
    -xf-vertical-text-alignment: center;
}

.createExpenseContainer {
    margin: 20 0 0 0;
    -xf-orientation: horizontal;
}

    .createExpenseContainer &amp;gt; entry {
        font-size: initial;
        background-color: #718096;
        color: #F7FAFC;
        -xf-placeholder-color: #CBD5E0;
    }

.expenseListItem {
    margin: 10 0 0 0;
    -xf-orientation: horizontal;
}

    .expenseListItem &amp;gt; label {
        font-size: 20;
        color: #F7FAFC;
    }

.noExpenses {
    font-size: 16;
    color: #A0AEC0;
    padding: 10;
    -xf-horizontal-text-alignment: center;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we have the styles sorted out we just need to add a bit of logic to the &lt;code&gt;HomePage&lt;/code&gt; component to load the right stylesheet based on the device's theme.&lt;/p&gt;

&lt;h3&gt;
  
  
  Loading the correct stylesheet
&lt;/h3&gt;

&lt;p&gt;We're going to add a new field to the &lt;code&gt;HomePage&lt;/code&gt; component which will store the theme. Then in the &lt;code&gt;OnInitializedAsync&lt;/code&gt; method we're going to set the field using the &lt;code&gt;AppInfo.RequestedTheme&lt;/code&gt; which is provided by Xamarin Essentials.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private AppTheme theme;

protected override async Task OnInitializedAsync()
{
    theme = AppInfo.RequestedTheme;

    // ... other code omitted
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we have that in place it's just a case of using it to load the correct stylesheet. At the top of the component where we declare the stylesheet we're going to replace it with the following code.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@if (theme == AppTheme.Light)
{
    &amp;lt;StyleSheet Resource="BudgetTrackerLight.css" Assembly="GetType().Assembly" /&amp;gt;
}
else if (theme == AppTheme.Dark)
{
    &amp;lt;StyleSheet Resource="BudgetTrackerDark.css" Assembly="GetType().Assembly" /&amp;gt;
}
else
{
    &amp;lt;StyleSheet Resource="BudgetTrackerLight.css" Assembly="GetType().Assembly" /&amp;gt;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I appreciate this isn't the most sophisticated code in the world, but for our simple app it will work nicely. We can now run the app and see how things have turned out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pg3F0Wtc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/themes-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pg3F0Wtc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/themes-1.jpg" alt="Mobile Blazor Bindings - Navigation and Xamarin Essentials"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We now have a nice dark mode for our Budget Tracker app which will adjust based on the users preference set on the device. And it was all pretty painless to setup thanks to the features provided by Xamarin Essentials!&lt;/p&gt;

&lt;p&gt;You can find the &lt;a href="https://github.com/chrissainty/mbb-budget-tracker"&gt;full source code on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this post, we've talked about navigation in Mobile Blazor Bindings, covering the current limitations in the framework. We then talked about Xamarin Essentials and what that offers us. We finished up by applying the &lt;em&gt;App Theme&lt;/em&gt; feature from Xamarin Essentials to the Budget Tracker app so that we could show a dark mode if the user had that set as their display preference.&lt;/p&gt;

&lt;p&gt;I hope you've enjoyed this series on Mobile Blazor Bindings and I've piqued your interest in the technology. As I've said many times through this series, this is an experiment and there is no official commitment to deliver this. So please only use it for fun right now. But if you're interested in seeing this become a real product, let the team know either via &lt;a href="https://github.com/xamarin/MobileBlazorBindings"&gt;GitHub&lt;/a&gt; or on &lt;a href="https://twitter.com/original_ejl"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>xamarinforms</category>
      <category>csharp</category>
      <category>dotnet</category>
      <category>blazor</category>
    </item>
    <item>
      <title>Mobile Blazor Bindings - State Management and Data</title>
      <dc:creator>Chris Sainty</dc:creator>
      <pubDate>Tue, 14 Apr 2020 08:00:00 +0000</pubDate>
      <link>https://dev.to/chrissainty/mobile-blazor-bindings-state-management-and-data-hj0</link>
      <guid>https://dev.to/chrissainty/mobile-blazor-bindings-state-management-and-data-hj0</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aKbzRrDh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/mobile-blazor-bindings-state-management-and-data.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aKbzRrDh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/mobile-blazor-bindings-state-management-and-data.jpg" alt="Mobile Blazor Bindings - State Management and Data"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Mobile Blazor Bindings for Web Developers Series
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Part 1&lt;/strong&gt; - &lt;a href="https://chrissainty.com/getting-started-with-mobile-blazor-bindings"&gt;Mobile Blazor Bindings - Getting Started&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Part 2&lt;/strong&gt; - &lt;a href="https://chrissainty.com/mobile-blazor-bindings-layout-and-styling"&gt;Mobile Blazor Bindings - Layout and Styling&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Part 3&lt;/strong&gt; - Mobile Blazor Bindings - State Management and Data &lt;em&gt;(this post)&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Last time, we looked at &lt;a href="https://dev.to/chrissainty/mobile-blazor-bindings-layout-and-styling-18ac"&gt;layout and styling&lt;/a&gt; options for Mobile Blazor Bindings (MBB). We learned about the various page types and layout components available to us, as well as how we could style our components using either parameter styling or the more familiar CSS approach. We finished up by applying what we learned to our Budget Tracker app, adding various layout components and styling to make the app look a bit more appealing.&lt;/p&gt;

&lt;p&gt;In this post, we're going to explore state management and data in MBB. We'll look at some option to manage the state of our applications ranging from simple to more complex. Then we'll talk about data, specifically, how to persist it. We'll cover how to deal with local persistence as well as persisting back to a server. Just as before, we'll finish up by applying what we've learned to our Budget Tracker app.&lt;/p&gt;

&lt;h2&gt;
  
  
  State Management
&lt;/h2&gt;

&lt;p&gt;Just as with web applications, we need to be able to manage the state of our mobile apps. Even in a simple app like Budget Tracker, we have various bits of state to keep track of.  The current budget, the current balance and the expenses that have been entered. Let's explore a couple of options we could use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storing state in components
&lt;/h3&gt;

&lt;p&gt;The simplest thing we can do when it comes to state is to manage it within a component. The Budget Tracker at the end of the last post stores and manages its state this way – all state is kept on the &lt;a href="https://github.com/chrissainty/mbb-budget-tracker/blob/ca6ca9dd8feb31f19d239b27ed5b3aa02d57a54d/src/BudgetTracker/Features/Home/HomePage.razor#L38"&gt;&lt;code&gt;HomePage&lt;/code&gt; component&lt;/a&gt;.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@code {

    private decimal _budget;
    private List&amp;lt;Expense&amp;gt; _expenses = new List&amp;lt;Expense&amp;gt;();

    private decimal _currentBalance =&amp;gt; _budget - _expenses.Sum(x =&amp;gt; x.Amount);
    private decimal _expensesTotal =&amp;gt; _expenses.Sum(x =&amp;gt; x.Amount);

}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The other components in the app update these values using Blazors &lt;a href="https://chrissainty.com/3-ways-to-communicate-between-components-in-blazor/#1-eventcallbacks"&gt;&lt;code&gt;EventCallback&lt;/code&gt;&lt;/a&gt; &lt;a href="https://chrissainty.com/3-ways-to-communicate-between-components-in-blazor/#1-eventcallbacks"&gt;approach&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This method works really well in simple scenarios such as the Budget Tracker app where there is only a single page component. But, depending on the app, in multi page apps this stops being a good option and we would need to look at something a bit more advanced.&lt;/p&gt;

&lt;h3&gt;
  
  
  AppState class
&lt;/h3&gt;

&lt;p&gt;The next level up would be implementing an &lt;code&gt;AppState&lt;/code&gt; class. We can record all the bits of state we need to keep track of across our application in this one place. This class is registered with the DI container as a &lt;code&gt;Singleton&lt;/code&gt;, giving all components we inject it into access to the same data.&lt;/p&gt;

&lt;p&gt;Say for example we had an ecommerce application. We could use an &lt;code&gt;AppState&lt;/code&gt; class to keep track of the contents of the shopping basket. It might look something like this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class AppState
{
    private readonly List&amp;lt;Item&amp;gt; _basket = new List&amp;lt;Item&amp;gt;();
    public IReadOnlyList&amp;lt;Item&amp;gt; Basket =&amp;gt; _basket.AsReadOnly();

    public event Action OnChange;

    public void AddItem(Item newItem)
    {
        _basket.Add(newItem);
        NotifyStateChanged();
    }

    public void RemoveItem(Item item)
    {
        _basket.Remove(item);
        NotifyStateChanged();
    }

    private void NotifyStateChanged() =&amp;gt; OnChange?.Invoke();
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You'll notice that the &lt;code&gt;Basket&lt;/code&gt; property is read only, this is important as we wouldn't want it being changed randomly. We want changes to go through the public methods, &lt;code&gt;AddItem&lt;/code&gt; and &lt;code&gt;RemoveItem&lt;/code&gt;, so we can ensure the &lt;code&gt;OnChange&lt;/code&gt; event is raised. All the components in our app that care about the state of the basket can subscribe to this event and be notified when updates happen.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@inject AppState AppState
@implements IDisposable

&amp;lt;StackLayout&amp;gt;
    &amp;lt;Label Text="@($"{AppState.Basket.Count} Items in Basket")" /&amp;gt;
&amp;lt;/StackLayout&amp;gt;

@code {

    protected override void OnInitialized()
    {
        AppState.OnChange += StateHasChanged;
    }

    public void Dispose() =&amp;gt; AppState.OnChange -= StateHasChanged;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the code above, whenever an item is added or removed from the basket the &lt;code&gt;OnChange&lt;/code&gt; event will trigger the component to re-render  by calling &lt;code&gt;StateHasChanged&lt;/code&gt;. We're also using implementing &lt;code&gt;IDisposable&lt;/code&gt; so we can safely unsubscribe from the &lt;code&gt;OnChange&lt;/code&gt; event when the component is destroyed.&lt;/p&gt;

&lt;p&gt;This method works really well and is pretty simple to implement and get going with. However, you may find it doesn't work well in large applications. The more state that's tracked the bigger the class gets as we add more methods to update the various values. Eventually, it will become quite difficult to navigate and maintain.&lt;/p&gt;

&lt;p&gt;At this point it would be worth looking at breaking the state down into smaller chunks, alternatively, you could also look at doing a &lt;a href="https://redux.js.org/"&gt;Redux&lt;/a&gt; or &lt;a href="https://mobx.js.org/README.html"&gt;MobX&lt;/a&gt; implementation for you MBB app. There &lt;a href="https://medium.com/@to_pe/xamarin-forms-with-redux-part-1-4a3a043cbc41"&gt;some example out there&lt;/a&gt; of implementing Redux in a Xamarin Forms app which should be fairly easy to port to MBB. I think the &lt;a href="https://github.com/mrpmorris/fluxor"&gt;Fluxor library&lt;/a&gt; from Peter Morris would also work, although I've not tested it myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data
&lt;/h2&gt;

&lt;p&gt;Let's talk about what we can do with our data. In mobile apps we have three scenarios we potentially need to cater for. Online, offline and a mix of both.&lt;/p&gt;

&lt;h3&gt;
  
  
  Online - Saving data to an API
&lt;/h3&gt;

&lt;p&gt;Saving data back to an API in MBB isn't much different to what we would do in a web based Blazor app, which is handy.&lt;/p&gt;

&lt;p&gt;There isn't an &lt;code&gt;HttpClient&lt;/code&gt; configured out of the box, so we need to install the &lt;code&gt;Microsoft.Extensions.Http&lt;/code&gt; NuGet package. Once installed we add the following line to register the various services with the DI container.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.ConfigureServices((hostContext, services) =&amp;gt;
{
    // Register app-specific services
    services.AddHttpClient();
})

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can also install the same &lt;code&gt;HttpClient&lt;/code&gt; helper methods we're used to from Blazor by adding the &lt;code&gt;System.Net.Http.Json&lt;/code&gt; package. This is currently a pre-release package, if you're not familiar with it you can read more about it in &lt;a href="https://devblogs.microsoft.com/aspnet/blazor-webassembly-3-2-0-preview-3-release-now-available/"&gt;this blog post&lt;/a&gt;. We now have access to &lt;code&gt;GetFromJsonAsync&lt;/code&gt;, &lt;code&gt;PostAsJsonAsync&lt;/code&gt; and &lt;code&gt;PutAsJsonAsync&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can now inject an &lt;code&gt;IHttpClientFactory&lt;/code&gt; into any component and use the &lt;code&gt;CreateClient&lt;/code&gt; method to get an instance of the &lt;code&gt;HttpClient&lt;/code&gt; to make our API calls with. From here things are the same as they would be in a web based Blazor app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Offline - Storing data on the device
&lt;/h3&gt;

&lt;p&gt;The most common option for storing data locally on the device is &lt;a href="https://www.sqlite.org/index.html"&gt;SQLite&lt;/a&gt;. It's a &lt;a href="https://www.sqlite.org/footprint.html"&gt;small&lt;/a&gt;, &lt;a href="https://www.sqlite.org/fasterthanfs.html"&gt;fast&lt;/a&gt;, &lt;a href="https://www.sqlite.org/selfcontained.html"&gt;self-contained&lt;/a&gt;, &lt;a href="https://www.sqlite.org/hirely.html"&gt;high-reliability&lt;/a&gt;, &lt;a href="https://www.sqlite.org/fullsql.html"&gt;full-featured&lt;/a&gt;, SQL database engine – it's also free and &lt;a href="https://github.com/sqlite/sqlite"&gt;open source&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using SQLite is really easy. Once the &lt;a href="https://www.nuget.org/packages/sqlite-net-pcl/"&gt;sqlite-net-pcl&lt;/a&gt; NuGet package is installed, we need to define entity classes, similar to how we would with Entity Framework. These represent the shape of the data we're going to persist. For example, if we were saving cars, a &lt;code&gt;Car&lt;/code&gt; entity could be defined like this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Car
{
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }
    public int Doors { get; set; }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is a simple POCO (Plain Old CLR Object/Plain Old C# Object) class the only bit of magic that's been added is the &lt;code&gt;PrimaryKey&lt;/code&gt; and &lt;code&gt;AutoIncrement&lt;/code&gt; attributes. These mark the primary key for the table and ensure it has an auto-incrementing value.&lt;/p&gt;

&lt;p&gt;Then we need to define a database class. this performs a few jobs. It ensures that the database is created along with any tables, it's also where we define any methods for saving or retrieving data. You can think of it as a mix between an Entity Framework DB context and a repository.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Database
{
    readonly SQLiteAsyncConnection _database;

    public Database(string dbPath)
    {
        _database = new SQLiteAsyncConnection(dbPath);
        _database.CreateTableAsync&amp;lt;Car&amp;gt;().Wait();
    }

    public Task&amp;lt;List&amp;lt;Car&amp;gt;&amp;gt; GetCarsAsync()
    {
        return _database.Table&amp;lt;Car&amp;gt;().ToListAsync();
    }

    public Task&amp;lt;int&amp;gt; SaveCarAsync(Car newCar)
    {
        return _database.InsertAsync(newCar);
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The final job is to add an instance of the &lt;code&gt;Database&lt;/code&gt; class into the DI container so we can using it by injecting it into our components.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public App()
{
    var database = new Database(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "cars.db3"));

    var host = MobileBlazorBindingsHost.CreateDefaultBuilder()
        .ConfigureServices((hostContext, services) =&amp;gt;
        {
            // Register app-specific services
            services.AddSingleton&amp;lt;Database&amp;gt;(database);
        })
        .Build();

        // other code omitted
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's all there is to it, data can now be saved locally on the device and will persist between app restarts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Both - Catering for offline scenarios
&lt;/h3&gt;

&lt;p&gt;The final option we'll look at is a mix of online and offline. This is probably the majority of mobile apps. And really this is about knowing if we're online or offline. If we're online we can make an API and if we're offline we can save data to a local database until the network is back and then push it up to the API. Now, we could just make API calls and see if they time out, then if they do, save locally. But this doesn't seem very elegant. Luckily for us there is a much simpler way thanks to Xamarin Essentials.&lt;/p&gt;

&lt;p&gt;We'll talk more about Xamarin Essentials another time but it's a great library which gives us access to loads of OS and platform APIs from C#, one of which is the &lt;a href="https://docs.microsoft.com/en-gb/xamarin/essentials/connectivity?context=xamarin%2Fxamarin-forms&amp;amp;tabs=android"&gt;Connectivity class&lt;/a&gt;. This gives us a simple API we can call to determine the network status of the device.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var current = Connectivity.NetworkAccess;

if (current == NetworkAccess.Internet)
{
    // Connection to internet is available
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can even subscribe to an event which will tell us when the network status changes.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public ConnectivityTest()
{
    // Register for connectivity changes, be sure to unsubscribe when finished
    Connectivity.ConnectivityChanged += HandleConnectivityChanged;
}

void HandleConnectivityChanged(object sender, ConnectivityChangedEventArgs e)
{
    // Do something based on new network status
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This gives us everything we need to be able to cater for scenarios where the app may not have a network connection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding State Management &amp;amp; Data to Budget Tracker
&lt;/h2&gt;

&lt;p&gt;Let's put everything together and apply it to Budget Tracker. Now, as I mentioned earlier, Budget Tracker can work perfectly fine with storing all its state on the &lt;code&gt;HomePage&lt;/code&gt; component. But using an &lt;code&gt;AppState&lt;/code&gt; class would clean up some of the code keeping everything in sync. Another advantage would come when persisting data. We aren't going to add an API to this project, that seems a bit overkill. But it would be great to be able to save data locally using SQLite. If we added an &lt;code&gt;AppState&lt;/code&gt; class we could do this much easier as everything is in one place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding an AppState Class
&lt;/h3&gt;

&lt;p&gt;We'll start by defining an &lt;code&gt;AppState&lt;/code&gt; class, in the root of the project, which contains all of the state which was originally kept in the &lt;code&gt;HomePage&lt;/code&gt; component.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class AppState
{
    private readonly List&amp;lt;Expense&amp;gt; _expenses = new List&amp;lt;Expense&amp;gt;();

    public decimal Budget { get; private set; }
    public IReadOnlyList&amp;lt;Expense&amp;gt; Expenses =&amp;gt; _expenses.AsReadOnly();
    public decimal CurrentBalance =&amp;gt; Budget - _expenses.Sum(x =&amp;gt; x.Amount);
    public decimal ExpensesTotal =&amp;gt; _expenses.Sum(x =&amp;gt; x.Amount);

    public event Action OnChange;

    public void SetBudget(decimal newBudget)
    {
        Budget = newBudget;
        NotifyStateChanged();
    }

    public void AddExpense(Expense newExpense)
    {
        _expenses.Add(newExpense);
        NotifyStateChanged();
    }

    private void NotifyStateChanged() =&amp;gt; OnChange?.Invoke();
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We're also going to register it as a singleton in the DI container in &lt;code&gt;App.cs&lt;/code&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var host = MobileBlazorBindingsHost.CreateDefaultBuilder()
    .ConfigureServices((hostContext, services) =&amp;gt;
    {
        // Register app-specific services
        services.AddSingleton&amp;lt;AppState&amp;gt;();
    })
    .Build();

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With those bits in place it's just a case of updating the various components to pull their state directly from the &lt;code&gt;AppState&lt;/code&gt; class. Here's what the updated &lt;code&gt;HomePage&lt;/code&gt; component looks like.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@inject AppState AppState
@implements IDisposable

&amp;lt;StyleSheet Resource="BudgetTracker.css" Assembly="GetType().Assembly" /&amp;gt;

&amp;lt;StackLayout class="homeContainer"&amp;gt;

    &amp;lt;Frame&amp;gt;
        &amp;lt;StackLayout&amp;gt;
            @if (AppState.Budget &amp;gt; 0)
            {
                &amp;lt;BudgetSummary /&amp;gt;
            }
            else
            {
                &amp;lt;SetBudget /&amp;gt;
            }
        &amp;lt;/StackLayout&amp;gt;
    &amp;lt;/Frame&amp;gt;

    @if (AppState.Budget &amp;gt; 0)
    {
        &amp;lt;Frame&amp;gt;
            &amp;lt;ScrollView&amp;gt;
                &amp;lt;StackLayout&amp;gt;
                    &amp;lt;Label Text="EXPENSES" /&amp;gt;
                    &amp;lt;ExpenseList /&amp;gt;
                    &amp;lt;CreateExpense /&amp;gt;
                &amp;lt;/StackLayout&amp;gt;
            &amp;lt;/ScrollView&amp;gt;
        &amp;lt;/Frame&amp;gt;
    }

&amp;lt;/StackLayout&amp;gt;

@code {

    protected override void OnInitialized() =&amp;gt; AppState.OnChange += StateHasChanged;

    public void Dispose() =&amp;gt; AppState.OnChange -= StateHasChanged;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can view all of the changes to the app over on the &lt;a href="https://github.com/chrissainty/mbb-budget-tracker"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Storing Data via SQLite
&lt;/h2&gt;

&lt;p&gt;Great! We now have the state of the app in a central place. Next we're going to add in SQLite so we can save the values we enter between app reboots. First we need to define our database class.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class BudgetTrackerDb
{
    private readonly SQLiteAsyncConnection _database;

    public BudgetTrackerDb(string dbPath)
    {
        _database = new SQLiteAsyncConnection(dbPath);
        _database.CreateTableAsync&amp;lt;Budget&amp;gt;().Wait();
        _database.CreateTableAsync&amp;lt;Expense&amp;gt;().Wait();
    }

    public async Task&amp;lt;int&amp;gt; SaveBudgetAsync(Budget newBudget)
    {
        var result = await _database.InsertAsync(newBudget);

        return result;
    }

    public async Task&amp;lt;decimal&amp;gt; GetBudgetAsync()
    {
        // This is nasty but as we're only going to have one budget for now so we'll let it slide
        var result = await _database.Table&amp;lt;Budget&amp;gt;().FirstOrDefaultAsync(x =&amp;gt; x.Amount &amp;gt; 0);

        return result?.Amount ?? 0;
    }
    public async Task&amp;lt;int&amp;gt; SaveExpenseAsync(Expense newExpense)
    {
        var result = await _database.InsertAsync(newExpense);

        return result;
    }

    public Task&amp;lt;List&amp;lt;Expense&amp;gt;&amp;gt; GetExpensesAsync()
    {
        return _database.Table&amp;lt;Expense&amp;gt;().ToListAsync();
    }

}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Our DB has two tables, one to store the budget and one to store the expenses. This setup would also allow us to expand the functionality of the app at a later data and support multiple budgets. We've also defined a few methods to save and retrieve data from the database.&lt;/p&gt;

&lt;p&gt;With the database class in place, next we're going to update our &lt;code&gt;AppState&lt;/code&gt; class.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class AppState
{
    private readonly BudgetTrackerDb _budgetTrackerDb;

    public AppState()
    {
        _budgetTrackerDb = new BudgetTrackerDb(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "BudgetTrackerDb.db3"));
    }

    public event Func&amp;lt;Task&amp;gt; OnChange;

    public async Task SetBudget(decimal newBudget)
    {
        _ = await _budgetTrackerDb.SaveBudgetAsync(new Budget { Amount = newBudget });
        await NotifyStateChanged();
    }

    public async Task&amp;lt;decimal&amp;gt; GetBudget() =&amp;gt; await _budgetTrackerDb.GetBudgetAsync();

    public async Task AddExpense(Expense newExpense)
    {
        _ = await _budgetTrackerDb.SaveExpenseAsync(newExpense);
        await NotifyStateChanged();
    }

    public async Task&amp;lt;IReadOnlyList&amp;lt;Expense&amp;gt;&amp;gt; GetExpenses() =&amp;gt; await _budgetTrackerDb.GetExpensesAsync();

    public async Task&amp;lt;decimal&amp;gt; GetCurrentBalance()
    {
        var budget = await GetBudget();
        var expenses = await GetExpenses();

        return budget - expenses.Sum(x =&amp;gt; x.Amount);
    }

    public async Task&amp;lt;decimal&amp;gt; GetTotalExpenses()
    {
        var expenses = await GetExpenses();

        return expenses.Sum(x =&amp;gt; x.Amount);
    }

    private async Task NotifyStateChanged() =&amp;gt; await OnChange?.Invoke();
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Essentially what we've done here is written methods which retrieve the data from our database rather than just storing the values in memory. An advantage of doing this is if our app needed to support online and offline functionality. We could easily add in a check to see if the app is connected or not, if it isn't then we could save locally to the SQLite database. But if it was then we could use a &lt;code&gt;HttpClient&lt;/code&gt; to send and retrieve data from an API. But the rest of our app wouldn't need to care, it could all be handled inside the &lt;code&gt;AppState&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;The final job now is to make some updates to the various components to work with the new methods. Here is the final &lt;code&gt;HomePage&lt;/code&gt; component.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@inject AppState AppState
@implements IDisposable

&amp;lt;StyleSheet Resource="BudgetTracker.css" Assembly="GetType().Assembly" /&amp;gt;

&amp;lt;StackLayout class="homeContainer"&amp;gt;

    &amp;lt;Frame&amp;gt;
        &amp;lt;StackLayout&amp;gt;
            @if (budgetSet)
            {
                &amp;lt;BudgetSummary /&amp;gt;
            }
            else
            {
                &amp;lt;SetBudget /&amp;gt;
            }
        &amp;lt;/StackLayout&amp;gt;
    &amp;lt;/Frame&amp;gt;

    @if (budgetSet)
    {
        &amp;lt;Frame&amp;gt;
            &amp;lt;ScrollView&amp;gt;
                &amp;lt;StackLayout&amp;gt;
                    &amp;lt;Label Text="EXPENSES" /&amp;gt;
                    &amp;lt;ExpenseList /&amp;gt;
                    &amp;lt;CreateExpense /&amp;gt;
                &amp;lt;/StackLayout&amp;gt;
            &amp;lt;/ScrollView&amp;gt;
        &amp;lt;/Frame&amp;gt;
    }

&amp;lt;/StackLayout&amp;gt;

@code {

    private bool budgetSet;

    protected override async Task OnInitializedAsync()
    {
        await UpdateState();
        AppState.OnChange += UpdateState;
    }

    public void Dispose() =&amp;gt; AppState.OnChange -= UpdateState;

    private async Task UpdateState()
    {
        var budget = await AppState.GetBudget();
        budgetSet = budget &amp;gt; 0;

        StateHasChanged();
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's it, we're done. You can see the full updated source code on the &lt;a href="https://github.com/chrissainty/mbb-budget-tracker"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this post we've looked at some options around managing state and storing data in a Mobile Blazor Bindings application.&lt;/p&gt;

&lt;p&gt;Starting with state, we looked at the most simple options first, state in components. We then moved on to a more advanced method using a central class called &lt;code&gt;AppState&lt;/code&gt; to store all state in the application.&lt;/p&gt;

&lt;p&gt;Next we looked at data and how we can store it locally on the device using SQLite, a popular, open source, portable SQL database. We talked about how we could configure MBB to make API calls using the &lt;code&gt;HttpClient&lt;/code&gt; so we could persist data back to the server. We also covered how we could use the Xamarin Essentials Connectivity class to determine if the app is connected in order to decide if data should be saved locally or an API call should be attempted.&lt;/p&gt;

&lt;p&gt;Finally, we applied some of our learnings to the Budget Tracker application. We added an &lt;code&gt;AppState&lt;/code&gt; class to hold all of the app state centrally. We also added in SQLite to store our budget and any expenses we'd added.&lt;/p&gt;

</description>
      <category>xamarinforms</category>
      <category>csharp</category>
      <category>dotnet</category>
      <category>blazor</category>
    </item>
    <item>
      <title>Mobile Blazor Bindings - Layout and Styling</title>
      <dc:creator>Chris Sainty</dc:creator>
      <pubDate>Tue, 07 Apr 2020 08:00:00 +0000</pubDate>
      <link>https://dev.to/chrissainty/mobile-blazor-bindings-layout-and-styling-18ac</link>
      <guid>https://dev.to/chrissainty/mobile-blazor-bindings-layout-and-styling-18ac</guid>
      <description>&lt;h2&gt;
  
  
  Mobile Blazor Bindings for Web Developers Series
&lt;/h2&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BRPZprhy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/mobile-blazor-bindings-layout-and-styling.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BRPZprhy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/mobile-blazor-bindings-layout-and-styling.jpg" alt="Mobile Blazor Bindings - Layout and Styling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the second post in the series: &lt;strong&gt;Mobile Blazor Bindings for Web Developers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 1&lt;/strong&gt; - &lt;a href="https://chrissainty.com/getting-started-with-mobile-blazor-bindings"&gt;Mobile Blazor Bindings - Getting Started&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Part 2&lt;/strong&gt; - Mobile Blazor Bindings - Layout and Styling &lt;em&gt;(this post)&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;In my &lt;a href="https://chrissainty.com/mobile-blazor-bindings-for-web-developers-getting-started/"&gt;part 1&lt;/a&gt;, I covered what Mobile Blazor Bindings (MBB) is, how to get your dev environment setup and create and run your first app. Over the next few posts we're going to exploring various topics to deepen our knowledge and help us build more feature rich, native mobile apps with MBB.&lt;/p&gt;

&lt;p&gt;In this post, we're going to look at layout and styling. In the web world, we're used to creating layouts and structure in our apps using elements such as &lt;code&gt;div&lt;/code&gt;s, &lt;code&gt;span&lt;/code&gt;s and &lt;code&gt;table&lt;/code&gt;s. These are then usually enhanced using CSS features such as flexbox, CSS grid or general CSS rules. When it comes to styling, everything we do uses CSS, we don't have any alternatives. So, how do we do this stuff in MBB? That's what we're going to find out.&lt;/p&gt;
&lt;h2&gt;
  
  
  Introducing Budget Tracker
&lt;/h2&gt;

&lt;p&gt;Before we get started, to give us a bit of focus over the coming posts, we're going to be working with a simple budget tracker app I've created. This will allow us to apply the various features we learn to a real app.&lt;/p&gt;

&lt;p&gt;I'm not going to go into loads of detail about the app as our goal here is to learn about Mobile Blazor Bindings, not budget tracking. I'll give a quick summary just so we understand the layout of the project.&lt;/p&gt;

&lt;p&gt;The app is very simple and can currently perform 3 tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set a budget for the month&lt;/li&gt;
&lt;li&gt;Record expenses&lt;/li&gt;
&lt;li&gt;Track the remaining balance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is what the project structure looks like.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Jm5Ohiaf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/solution-structure-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Jm5Ohiaf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/solution-structure-1.jpg" alt="Mobile Blazor Bindings - Layout and Styling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm a big fan of feature folders to organise projects, you can see them in use here. There's a top level feature called &lt;code&gt;Home&lt;/code&gt; which has a single page component called &lt;code&gt;HomePage&lt;/code&gt; – I tend to postfix any page components with &lt;code&gt;Page&lt;/code&gt; so they are easily distinguishable from regular components. Then there are two sub-features, &lt;code&gt;BudgetManagement&lt;/code&gt; and &lt;code&gt;ExpenseManagement&lt;/code&gt;. The contain regular components which are loaded into the &lt;code&gt;HomePage&lt;/code&gt; based on certain logic.&lt;/p&gt;

&lt;p&gt;The project is &lt;a href="https://github.com/chrissainty/mbb-budget-tracker"&gt;available on GitHub&lt;/a&gt; so you can check it out and play with it at your leisure. As I said, we'll be evolving it over the next few posts so it may change from the above structure over time.&lt;/p&gt;

&lt;p&gt;Let's crack on and starting looking at layout options for our app.&lt;/p&gt;
&lt;h2&gt;
  
  
  Layout Options
&lt;/h2&gt;

&lt;p&gt;When compared to the web, our options for layouts in MBB are far more structured. As I mentioned in the intro, when creating web apps we tend to use a lot of &lt;code&gt;div&lt;/code&gt; elements with CSS to add structure to our pages. But the &lt;code&gt;div&lt;/code&gt; element is just a divider, something that marks a section of an HTML document. Other than being a block element (&lt;code&gt;display: block;&lt;/code&gt;), it has no predefined abilities. This can be useful as it makes it flexible, however, we have to define what we want a particular &lt;code&gt;div&lt;/code&gt; to do every time.&lt;/p&gt;

&lt;p&gt;With MBB this is not the case, we have access to a set of predefined structural components allowing us to rapidly create interesting and efficient UI. There are two categories of component for this, page components and layout components.&lt;/p&gt;
&lt;h3&gt;
  
  
  Page Components
&lt;/h3&gt;

&lt;p&gt;Different page types is not something we're used to in the web world. We have a single page type, a HTML document, and that's it. It's certainly possible to create the kinds of page configurations offered by MBB in HTML, but it involves us having to do all the configuration manually and can take a lot of time.&lt;/p&gt;

&lt;p&gt;With MBB, at the time of writing, there are three ready to use page components out of the box (checkout the&lt;a href="https://docs.microsoft.com/en-us/mobile-blazor-bindings/ui/components-reference"&gt;latest list here&lt;/a&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-gb/xamarin/xamarin-forms/user-interface/controls/pages#contentpage"&gt;&lt;strong&gt;ContentPage&lt;/strong&gt;&lt;/a&gt;
The most commonly used type of page. This is a simple component which can display a single piece of child content. For example, a &lt;code&gt;StackLayout&lt;/code&gt; or &lt;code&gt;Grid&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-gb/xamarin/xamarin-forms/user-interface/controls/pages#masterdetailpage"&gt;&lt;strong&gt;MasterDetailPage&lt;/strong&gt;&lt;/a&gt;
This page displays a master view, often set to display a menu. And a detail view, set to display the selected menu item. This is a great starting point for multi-page apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.microsoft.com/en-gb/xamarin/xamarin-forms/user-interface/controls/pages#tabbedpage"&gt;TabbedPage&lt;/a&gt;&lt;/strong&gt;
Allows the developers to define a set of tabs which, when clicked, load their content in to the main view.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are also two lower level components which can be used to create your own custom page types.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/xamarin.forms.page?view=xamarin-forms"&gt;&lt;strong&gt;Page&lt;/strong&gt;&lt;/a&gt;
Page is essentially a base class used for creating more functional derived types, all of the other page components here derive from this class. You could use this as a starting point for creating your own custom page type.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-gb/xamarin/xamarin-forms/user-interface/controls/pages#templatedpage"&gt;&lt;strong&gt;TemplatedPage&lt;/strong&gt;&lt;/a&gt;
Derives from the &lt;code&gt;Page&lt;/code&gt; component above. This component displays full-screen content with a control template and is the base class for the &lt;code&gt;ContentPage&lt;/code&gt; component.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Layout Components
&lt;/h3&gt;

&lt;p&gt;In MBB, we can use dedicated layout components. At the time of writing there are five layout components available (you can checkout the &lt;a href="https://docs.microsoft.com/en-us/mobile-blazor-bindings/ui/components-reference#built-in-components"&gt;current list in the docs&lt;/a&gt;). They are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-gb/xamarin/xamarin-forms/user-interface/controls/layouts#contentview"&gt;&lt;strong&gt;ContentView&lt;/strong&gt;&lt;/a&gt;
This is a simple structural component which can display a single child. The child can be any &lt;a href="https://docs.microsoft.com/en-us/mobile-blazor-bindings/ui/components-reference#built-in-components"&gt;view component&lt;/a&gt; or layout component. &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-gb/xamarin/xamarin-forms/user-interface/controls/layouts#frame"&gt;&lt;strong&gt;Frame&lt;/strong&gt;&lt;/a&gt;
Frame derives from &lt;code&gt;ContentView&lt;/code&gt; and, by default, displays its child content with a border and shadow making it stand out on the screen. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.microsoft.com/en-gb/xamarin/xamarin-forms/user-interface/controls/layouts#grid"&gt;Grid&lt;/a&gt;&lt;/strong&gt;
Unsurprisingly, this component allows its child content to be displayed in a grid of rows and columns. This is equivalent to an HTML &lt;code&gt;table&lt;/code&gt; element.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-gb/xamarin/xamarin-forms/user-interface/controls/layouts#scrollview"&gt;&lt;strong&gt;ScrollView&lt;/strong&gt;&lt;/a&gt;
This component allows its content to be scrollable, very useful when displaying long lists or large amounts of text. &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-gb/xamarin/xamarin-forms/user-interface/controls/layouts#stacklayout"&gt;&lt;strong&gt;StackLayout&lt;/strong&gt;&lt;/a&gt;
Child components are displayed in a vertical stack, by default. This can be swapped to horizontal by setting the &lt;code&gt;Orientation&lt;/code&gt; parameter. This is the most common layout component I've used so far – the &lt;code&gt;div&lt;/code&gt; of the MBB world if you will.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Styling
&lt;/h2&gt;

&lt;p&gt;Now we know about the various options available to use for structuring our pages, what about styling them? MBB offers us two options here, what I'm going to call parameter styles, and CSS styles.&lt;/p&gt;
&lt;h3&gt;
  
  
  Parameter Styles
&lt;/h3&gt;

&lt;p&gt;Parameter based styling is very similar to what Xamarin Forms refers to as XAML styles. When styling apps using this method we set all style related settings on the component using its exposed parameters.&lt;/p&gt;

&lt;p&gt;This is probably easier to understand with an example. Let's say we wanted to style a &lt;code&gt;Label&lt;/code&gt; with a font size of 30 and have it's text coloured blue. This is how we would do that using parameter styles.&lt;/p&gt;




&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Label Text="EXPENSES"
       FontSize="30"
       TextColor="Color.Blue" /&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;p&gt;We can also set other types of style information for components which is specific to the underlying Xamarin Forms platform. For example, a &lt;code&gt;StackLayout&lt;/code&gt; stacks it's child content vertically by default. We can change this to horizontal by using the &lt;code&gt;Orientation&lt;/code&gt; parameter.&lt;/p&gt;




&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;StackLayout Orientation="StackOrientation.Horizontal"&amp;gt;
    &amp;lt;!-- ... other code omitted ... --&amp;gt;
&amp;lt;/StackLayout&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;p&gt;This method of styling is pretty quick to get going with and it makes it very clear what styles are applied to which components. But one big downside is that we have to set styles everywhere, we can't just predefine a style for all &lt;code&gt;Label&lt;/code&gt;s globally, we have to set each one individually.&lt;/p&gt;

&lt;p&gt;Let's look at the other options now which is much more familiar to us web devs, CSS.&lt;/p&gt;
&lt;h3&gt;
  
  
  CSS Styles
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Please Note:&lt;/strong&gt; CSS styles don't appear to work correctly in the &lt;a href="https://www.nuget.org/packages/Microsoft.MobileBlazorBindings/0.2.42-preview"&gt;current offical release&lt;/a&gt; (v0.2.42-preview). In order to use them, I've had to clone the repo and build my own NuGet packages to get the latest changes. Hopefully a new release will be out shortly and this step won't be needed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Styling components using CSS is probably the obvious go-to option if you're coming from a web background, and it works pretty much how you would expect it to in MBB. We can create style classes and apply them to individual components or we can use CSS selectors to target all &lt;code&gt;Label&lt;/code&gt;s in an app.&lt;/p&gt;

&lt;p&gt;We create a stylesheet as normal to contain our styles and we reference it in each page of our app using a special component called &lt;code&gt;StyleSheet&lt;/code&gt; which looks like this.&lt;/p&gt;




&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;StyleSheet Resource="BudgetTracker.css" Assembly="GetType().Assembly" /&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;blockquote&gt;
&lt;p&gt;Don't put the &lt;code&gt;StyleSheet&lt;/code&gt; component inside any layout components otherwise things won't work and you'll probably get a load of weird exceptions – trust me I lost a few hours to this 😭.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another thing to be aware of is that right now stylesheets need to be at the root of your project, they don't appear to work when moved into folders. There is a &lt;a href="https://github.com/xamarin/MobileBlazorBindings/issues/103"&gt;issue tracking this&lt;/a&gt; on the GitHub repo.&lt;/p&gt;

&lt;p&gt;Using the examples we looked at with parameter styles, what do they look like using CSS. For our first example, we could create a normal style class in our stylesheet with the following rules.&lt;/p&gt;




&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.largeBlueLabel {
    font-size: 30;
    colour: blue;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;p&gt;Then apply it to the relevant component using the &lt;code&gt;class&lt;/code&gt; parameter.&lt;/p&gt;




&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Label Text="EXPENSES"
       class="largeBlueLabel" /&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;p&gt;Pretty simple right?! But what about handling the Xamarin Forms specific styling such as the orientation example? Well we can do that with CSS as well!&lt;/p&gt;

&lt;p&gt;The CSS in MBB is a special flavour which includes a load of specific &lt;a href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/styles/css/#selector-reference"&gt;selectors&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/styles/css/#xamarinforms-specific-properties"&gt;properties&lt;/a&gt;. Which means we can manipulate setting such as orientation via CSS as well.&lt;/p&gt;




&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.horizontal {
    -xf-orientation: horizontal;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&amp;lt;!--kg-card-end: markdown--&amp;gt;&amp;lt;!--kg-card-begin: markdown--&amp;gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;StackLayout class="horizontal"&amp;gt;
    &amp;lt;!-- ... other code omitted ... --&amp;gt;
&amp;lt;/StackLayout&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In these examples the changes aren't huge but imagine if we'd set several style parameters on a component, the markup starts to look noisy really quick. Using CSS also allows us to remove the issue we identified with parameter styling where we need to set the same styles over and over again. With CSS we can define the class once and just apply it to whatever components we choose.&lt;/p&gt;

&lt;p&gt;Now we have all of this new knowledge about how to layout and style Mobile Blazor Bindings apps, let's put some of it into action but applying it to the budget tracker app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Layout &amp;amp; Styling to Budget Tracker
&lt;/h2&gt;

&lt;p&gt;We don't really need more than one page in our app, at least for now. We'll keep the default page type, which is a &lt;code&gt;ContentPage&lt;/code&gt;, and we'll focus on applying layout components and styling.&lt;/p&gt;

&lt;p&gt;Just for reference, if you check the &lt;code&gt;App.cs&lt;/code&gt; you can see where the &lt;code&gt;HomePage&lt;/code&gt; component is set as the child of the &lt;code&gt;ContentPage&lt;/code&gt;.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MainPage = new ContentPage();
host.AddComponent&amp;lt;HomePage&amp;gt;(parent: MainPage);

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's start applying some of these layout components to our app. Currently the app has no layout components at all. This is the code for the &lt;code&gt;HomePage&lt;/code&gt; component.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@if (_budget &amp;gt; 0)
{
    &amp;lt;BudgetSummary Budget="_budget"
                   TotalExpenses="_expensesTotal"
                   CurrentBalance="_currentBalance" /&amp;gt;
}
else
{
    &amp;lt;SetBudget OnBudgetSet="@((newBudget) =&amp;gt; _budget = newBudget)" /&amp;gt;
}

@if (_budget &amp;gt; 0)
{
    &amp;lt;Label Text="EXPENSES" /&amp;gt;
    &amp;lt;ExpenseList Expenses="_expenses" /&amp;gt;
    &amp;lt;CreateExpense OnExpenseAdded="@((newExpense) =&amp;gt; _expenses.Add(newExpense))" /&amp;gt;
}

@code {

    private decimal _budget;
    private List&amp;lt;Expense&amp;gt; _expenses = new List&amp;lt;Expense&amp;gt;();

    private decimal _currentBalance =&amp;gt; _budget - _expenses.Sum(x =&amp;gt; x.Amount);
    private decimal _expensesTotal =&amp;gt; _expenses.Sum(x =&amp;gt; x.Amount);

}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What does this look like when we run it?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UdeaMXpk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/no-layout-components.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UdeaMXpk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/no-layout-components.jpg" alt="Mobile Blazor Bindings - Layout and Styling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Umm... not the best, I think you'll agree. As our budget is currently 0 the &lt;code&gt;SetBudget&lt;/code&gt; component is being displayed, which looks like this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Label Text="SET YOUR BUDGET" /&amp;gt;
&amp;lt;Label Text="£" /&amp;gt;
&amp;lt;Entry @bind-Text="Budget"
       OnCompleted="@(() =&amp;gt; OnBudgetSet.InvokeAsync(_budget))" /&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But where are all the other UI elements? All we are seeing is the &lt;code&gt;Entry&lt;/code&gt; component – equivalent to an HTML input control – This is because the &lt;code&gt;HomePage&lt;/code&gt; component is being displayed in a &lt;code&gt;ContentPage&lt;/code&gt; which, as we learned earlier, can only display one child. It seems the last component wins, in this case the &lt;code&gt;Entry&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;At the very least we need a single top level component to contain all our content. Let's add a &lt;code&gt;StackLayout&lt;/code&gt; to our &lt;code&gt;HomePage&lt;/code&gt; and see what happens.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;StackLayout&amp;gt;
    @if (_budget &amp;gt; 0)
    {
        &amp;lt;BudgetSummary Budget="_budget"
                       TotalExpenses="_expensesTotal"
                       CurrentBalance="_currentBalance" /&amp;gt;
    }
    else
    {
        &amp;lt;SetBudget OnBudgetSet="@((newBudget) =&amp;gt; _budget = newBudget)" /&amp;gt;
    }

    @if (_budget &amp;gt; 0)
    {
        &amp;lt;Label Text="EXPENSES" /&amp;gt;
        &amp;lt;ExpenseList Expenses="_expenses" /&amp;gt;
        &amp;lt;CreateExpense OnExpenseAdded="@((newExpense) =&amp;gt; _expenses.Add(newExpense))" /&amp;gt;
    }
&amp;lt;/StackLayout&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D25Ek5EM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/single-stacklayout.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D25Ek5EM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/single-stacklayout.jpg" alt="Mobile Blazor Bindings - Layout and Styling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's looking a bit better, we can see all 3 UI elements, the 2 &lt;code&gt;Label&lt;/code&gt;s and the &lt;code&gt;Entry&lt;/code&gt;.  As we found out earlier, child components in a &lt;code&gt;StackLayout&lt;/code&gt; are stacked vertically by default, but it would be much nicer if the &lt;code&gt;£&lt;/code&gt; symbol and the &lt;code&gt;Entry&lt;/code&gt; were on the same line. We can add another &lt;code&gt;StackLayout&lt;/code&gt; around the &lt;code&gt;Label&lt;/code&gt; and the &lt;code&gt;Entry&lt;/code&gt; and set it to display horizontally, which should achieve what we're after.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Label Text="SET YOUR BUDGET" /&amp;gt;
&amp;lt;StackLayout Orientation="StackOrientation.Horizontal"&amp;gt;
    &amp;lt;Label Text="£" /&amp;gt;
    &amp;lt;Entry @bind-Text="Budget"
           OnCompleted="@(() =&amp;gt; OnBudgetSet.InvokeAsync(_budget))" /&amp;gt;
&amp;lt;/StackLayout&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7tXfOKFN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/setbudget-horizontal-stacklayout.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7tXfOKFN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/setbudget-horizontal-stacklayout.jpg" alt="Mobile Blazor Bindings - Layout and Styling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We now have the layout that we wanted but it's looks pretty naff. Let's apply some styling to try and improve things a bit.&lt;/p&gt;

&lt;p&gt;First off we'll apply some parameter styles as its a pretty quick way to try things out.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Label Text="SET YOUR BUDGET" /&amp;gt;
&amp;lt;StackLayout Orientation="StackOrientation.Horizontal"&amp;gt;
    &amp;lt;Label Text="£"
           TextColor="@(Color.FromHex("718096"))"
           FontSize="30"
           VerticalTextAlignment="TextAlignment.Center" /&amp;gt;
    &amp;lt;Entry FontSize="30"
           TextColor="@(Color.FromHex("2D3748"))"
           HorizontalOptions="LayoutOptions.FillAndExpand"
           @bind-Text="Budget"
           OnCompleted="@(() =&amp;gt; OnBudgetSet.InvokeAsync(_budget))" /&amp;gt;
&amp;lt;/StackLayout&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MEtJbAjt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/setbudget-parameter-styles.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MEtJbAjt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/setbudget-parameter-styles.jpg" alt="Mobile Blazor Bindings - Layout and Styling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's now looking loads better but as I mentioned earlier, there is a lot of markup added just for a few style tweaks. Let's swap this over to CSS styles and see what it looks like.&lt;/p&gt;

&lt;p&gt;We first need to create a stylesheet in the root of the project, we'll call it &lt;code&gt;BudgetTracker.css&lt;/code&gt; and then add a reference to it in the &lt;code&gt;HomePage&lt;/code&gt; component.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;StyleSheet Resource="BudgetTracker.css" Assembly="GetType().Assembly" /&amp;gt;

&amp;lt;StackLayout&amp;gt;
    &amp;lt;!-- ... other code omitted ... --&amp;gt;
&amp;lt;/StackLayout&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can then add the following styles to our stylesheet and adjust the markup to use these new styles.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;entry {
    font-size: 30;
    color: #2D3748;
}

.currencySymbol {
    color: #718096;
    font-size: 30;
    -xf-vertical-text-alignment: center;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&amp;lt;!--kg-card-end: markdown--&amp;gt;&amp;lt;!--kg-card-begin: markdown--&amp;gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Label Text="SET YOUR BUDGET" /&amp;gt;
&amp;lt;StackLayout Orientation="StackOrientation.Horizontal"&amp;gt;
    &amp;lt;Label Text="£"
           class="currencySymbol" /&amp;gt;
    &amp;lt;Entry HorizontalOptions="LayoutOptions.FillAndExpand"
           @bind-Text="Budget"
           OnCompleted="@(() =&amp;gt; OnBudgetSet.InvokeAsync(_budget))" /&amp;gt;
&amp;lt;/StackLayout&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The final change we will make is to add in a &lt;code&gt;Frame&lt;/code&gt; component to make our set budget section stand out. We'll start by adding a new CSS class with some styling, then adjust the markup.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.setBudgetContainer {
    border-radius: 10;
    background-color: #ffffff;
    margin: 10;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&amp;lt;!--kg-card-end: markdown--&amp;gt;&amp;lt;!--kg-card-begin: markdown--&amp;gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Frame class="setBudgetContainer"&amp;gt;
    &amp;lt;StackLayout&amp;gt;
        &amp;lt;Label Text="SET YOUR BUDGET" /&amp;gt;
        &amp;lt;StackLayout Orientation="StackOrientation.Horizontal"&amp;gt;
            &amp;lt;Label Text="£"
                   class="currencySymbol" /&amp;gt;
            &amp;lt;Entry ClearButtonVisibility="ClearButtonVisibility.WhileEditing"
                   HorizontalOptions="LayoutOptions.FillAndExpand"
                   @bind-Text="Budget"
                   OnCompleted="@(() =&amp;gt; OnBudgetSet.InvokeAsync(_budget))" /&amp;gt;
        &amp;lt;/StackLayout&amp;gt;
    &amp;lt;/StackLayout&amp;gt;
&amp;lt;/Frame&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Like other layout components we talked about earlier, the &lt;code&gt;Frame&lt;/code&gt; component can only have a single child, so we need to add an additional &lt;code&gt;StackLayout&lt;/code&gt; to wrap the existing &lt;code&gt;Label&lt;/code&gt; and &lt;code&gt;StackLayout&lt;/code&gt; – told you &lt;code&gt;StackLayout&lt;/code&gt;s are the &lt;code&gt;div&lt;/code&gt; of the MBB world! 😂. With the above changes our app now looks like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1Z1LohWZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/setbudget-complete.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1Z1LohWZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/04/setbudget-complete.jpg" alt="Mobile Blazor Bindings - Layout and Styling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our app now looks loads better, obviously we still need to apply layout and styling to the rest of it, but I think this blog post is long enough already! So, if you've made it this far then well done and thank you. I'll carry on with styling the app and you can check it out on &lt;a href="https://github.com/chrissainty/mbb-budget-tracker"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this post I've introduced the layout and styling options available to us in Mobile Blazor Bindings. I briefly introduced the Budget Tracker app we'll be developing over the course of this series.&lt;/p&gt;

&lt;p&gt;Then I talked about the layout options available in MBB, this included all the current page components and layout components. We learned about what each one offers us before moving on to talk about styling. In terms of styling we found out we had two options, parameter styling or CSS. We looked at examples of how to use each one and talked about some potential downsides of parameter styling and how CSS styles could solves those problems.&lt;/p&gt;

&lt;p&gt;Finally, we took what we learned and applied to the Budget Tracker app. We added some layout components to improve the look of the page and then added some styles. We first tried parameter styling and then quickly moved to CSS styles.&lt;/p&gt;

</description>
      <category>xamarinforms</category>
      <category>csharp</category>
      <category>dotnet</category>
      <category>blazor</category>
    </item>
    <item>
      <title>Getting Started with Mobile Blazor Bindings</title>
      <dc:creator>Chris Sainty</dc:creator>
      <pubDate>Wed, 01 Apr 2020 08:00:00 +0000</pubDate>
      <link>https://dev.to/chrissainty/getting-started-with-mobile-blazor-bindings-3k39</link>
      <guid>https://dev.to/chrissainty/getting-started-with-mobile-blazor-bindings-3k39</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--czzRQSns--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/mobile-blazor-bindings-for-web-developers-getting-started.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--czzRQSns--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/mobile-blazor-bindings-for-web-developers-getting-started.jpg" alt="Getting Started with Mobile Blazor Bindings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the first, in what will probably be a series of blog posts, I've been looking forward to writing for a while – I'm going to be exploring the new &lt;strong&gt;&lt;u&gt;experimental &lt;/u&gt;&lt;/strong&gt; Mobile Blazor Bindings project.&lt;/p&gt;

&lt;p&gt;In this post, I'm going to be giving an introduction to the Mobile Blazor Bindings (MBB) project, what it is, why you might be interesting in trying it, what is and isn't available and we'll finish with creating our first app.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Mobile Blazor Bindings?
&lt;/h2&gt;

&lt;p&gt;It's a new &lt;strong&gt;&lt;u&gt;experimental&lt;/u&gt;&lt;/strong&gt; project led by &lt;a href="https://twitter.com/original_ejl"&gt;Eilon Lipton&lt;/a&gt;, a principal software engineer at Microsoft. The unique selling point of the project is it enables developers to author native, cross platform mobile apps using Blazors programming model.&lt;/p&gt;

&lt;p&gt;What this means is instead of writing a mix of C# and HTML to create components, as we would in the web hosting models for Blazor, we write C# and native mobile controls. To give you an idea of what this looks like, below is a counter component written for a Blazor WebAssembly application, then below that is that same component but written for MBB.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- Blazor WebAssembly --&amp;gt;

&amp;lt;p&amp;gt;Current count: @currentCount&amp;lt;/p&amp;gt;
&amp;lt;button class="btn btn-primary" @onclick="IncrementCount"&amp;gt;Click me&amp;lt;/button&amp;gt;

@code {
    int currentCount = 0;

    void IncrementCount()
    {
        currentCount++;
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&amp;lt;!--kg-card-end: markdown--&amp;gt;&amp;lt;!--kg-card-begin: markdown--&amp;gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- Mobile Blazor Bindings --&amp;gt;

&amp;lt;Label Text="@($"Current count: {currentCount}")" /&amp;gt;
&amp;lt;Button Text="Click me" OnClick="@IncrementCount" /&amp;gt;

@code
{
    int currentCount = 0;

    void IncrementCount()
    {
        currentCount++;
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see the programming model is identical, it's just the types of controls which are used that is different. This makes MBB a great stepping stone for web developers looking to get into cross platform native mobile app development, using their existing skills.&lt;/p&gt;

&lt;p&gt;The components we use to author apps with MBB are essentially wrappers around Xamarin Forms controls. At the time of writing, the following components are available.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Page components&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ContentPage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MasterDetailPage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Page&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TabbedPage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TemplatedPage&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Layout components&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ContentView&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Frame&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Grid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ScrollView&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;StackLayout&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;View components&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ActivityIndicator&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BoxView&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Button&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CheckBox&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Image&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ImageButton&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Entry&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Label&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ProgressBar&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Slider&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Stepper&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Switch&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Specialized components&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Application&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BaseMenuItem&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FormattedString&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GestureElement&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MenuItem&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Shell&lt;/code&gt; (including &lt;code&gt;ShellContent&lt;/code&gt;, &lt;code&gt;ShellGroupItem&lt;/code&gt;, &lt;code&gt;ShellItem&lt;/code&gt;, &lt;code&gt;FlyoutItem&lt;/code&gt;, &lt;code&gt;TabBar&lt;/code&gt;, &lt;code&gt;ShellSection&lt;/code&gt;, &lt;code&gt;Tab&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Span&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can checkout the &lt;a href="https://docs.microsoft.com/en-gb/mobile-blazor-bindings/ui/components-reference"&gt;official docs&lt;/a&gt; to get the most up-to-date information on the current components available.&lt;/p&gt;

&lt;p&gt;After reading the above, a few questions may be going round in your head, &lt;em&gt;what about Xamarin?&lt;/em&gt; &lt;em&gt;Do they know about this? Is Xamarin being replaced?&lt;/em&gt; These are all good questions so let's cover those next.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about Xamarin? Is it being replaced?
&lt;/h2&gt;

&lt;p&gt;The first thing to point out is that MBB is just an experiment, there is no commitment to developing and delivering this as a product. When the &lt;a href="https://devblogs.microsoft.com/aspnet/mobile-blazor-bindings-experiment/"&gt;first version of MBB was announced&lt;/a&gt;, the blog post contained the following statement.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We have heard from a set of developers that come from a web programming background that having web specific patterns to build mobile applications would be ideal for them. The goal of these bindings is to see if developers would like to have the option of writing markup and doing data binding for native mobile applications using the Blazor-style programming model with Razor syntax and features.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The key part to pull out is &lt;em&gt;"if developers would like to have the &lt;strong&gt;option&lt;/strong&gt;"&lt;/em&gt;. MBB, if was taken forward, would offer an alternative to writing native mobile apps using XAML.&lt;/p&gt;

&lt;p&gt;I think this is a great idea and I'm keen to see where it goes, the big thing keeping me away from native mobile development is XAML, I just don't like it. That's not to say there is anything wrong with it, I know a lot of developers really enjoy working with it. I also know a lot of developers also feel the same way about HTML.&lt;/p&gt;

&lt;p&gt;I think giving developers the choice to write apps using the languages they enjoy, and have skills in, is a fantastic thing. The likes of Uno Platform are offering the same choice the other way, allowing developers familiar with XAML the option to write web applications using that instead of HTML. Everyone wins!&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Setup
&lt;/h2&gt;

&lt;p&gt;Now we've gotten a better understanding of what MBB is and why we might want to try it out. Let's move on and get setup so we can start playing with it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Workloads
&lt;/h3&gt;

&lt;p&gt;You can try out MBB using either Visual Studio or Visual Studio for Mac, but you will need to install the following workloads:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mobile development with .NET&lt;/li&gt;
&lt;li&gt;ASP.NET and web development&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Cr7-aeLy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/xamarin-workload-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Cr7-aeLy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/xamarin-workload-1.jpg" alt="Getting Started with Mobile Blazor Bindings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have installed the above workloads, if you don't already have it, you will also need to download and install the &lt;a href="https://dotnet.microsoft.com/download"&gt;latest version of the .NET SDK&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing the MBB Template
&lt;/h3&gt;

&lt;p&gt;There is a project template we need to use to create new MBB applications, this can be installed using the dotnet CLI using the following command (you may want to &lt;a href="https://www.nuget.org/packages/Microsoft.MobileBlazorBindings.Templates/"&gt;check for a newer version of the templates&lt;/a&gt; before installing).&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet new -i Microsoft.MobileBlazorBindings.Templates::0.2.42-preview

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once you have the template installed, you should be able to see it when running the &lt;code&gt;dotnet new&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--toqaikAP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/dotnet-new-template.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--toqaikAP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/dotnet-new-template.jpg" alt="Getting Started with Mobile Blazor Bindings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Enabling Windows Hypervisor Platform
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aCOiEWaJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/improve-emulator-experience.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aCOiEWaJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/improve-emulator-experience.jpg" alt="Getting Started with Mobile Blazor Bindings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was something I bumped into when I first tried to run the Android emulator from Visual Studio. I then had to go and enable it which then required a restart of my PC. So I want to save you a bit of time and let you know about it now.&lt;/p&gt;

&lt;p&gt;Windows Hypervisor Platform will greatly improve the performance of the Android emulator when working with MBB, or any Xamarin application for that matter. If you follow &lt;a href="https://docs.microsoft.com/en-us/xamarin/android/get-started/installation/android-emulator/hardware-acceleration?tabs=vswin&amp;amp;pivots=windows"&gt;this link&lt;/a&gt;, full instructions are given on how to enable WHP on your machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an MBB app
&lt;/h2&gt;

&lt;p&gt;Once you've completed the above steps you should be ready to create your first Mobile Blazor Bindings application!&lt;/p&gt;

&lt;p&gt;Currently there is no integration with the new project dialogue in Visual Studio so we will need to create the app from the command line using the dotnet CLI. To create a new MBB app use the following command (I've called my app &lt;em&gt;HelloMBB&lt;/em&gt; but call yours whatever you want):&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet new mobileblazorbindings -o HelloMBB

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can now open Visual Studio and load up the solution. You should see 3 projects in the Solution Explorer, &lt;code&gt;HelloMBB&lt;/code&gt;, &lt;code&gt;HelloMBB.Android&lt;/code&gt; and &lt;code&gt;HelloMBB.iOS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--swQvQMgo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/initial-project-structure.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--swQvQMgo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/initial-project-structure.jpg" alt="Getting Started with Mobile Blazor Bindings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Android and iOS projects are essentially shells for the particular platform which our MBB app is going to load into. All of the application logic is kept in the &lt;code&gt;HelloMBB&lt;/code&gt; project.&lt;/p&gt;

&lt;p&gt;This is the same approach you can use to run a Blazor web app using either the Server or WebAssembly hosting model. Putting all common components into a &lt;code&gt;RazorClassLibrary&lt;/code&gt; and removing everything but the infrastructure code from the Server and WebAssembly projects. You can find an example of that &lt;a href="https://github.com/chrissainty/ddd-reading-2019/tree/master/Demos/src/CodeSharingWithBlazor"&gt;approach on my GitHub&lt;/a&gt; if you've not seen it before.&lt;/p&gt;

&lt;p&gt;If you want to run the iOS project you're going to need a Mac in order to compile the project. This is due to Apples licencing and there isn't a way around it. I do have a Mac but I'm current working on a Windows machine so, for now, I'm going to set the Android project as the startup project and then hit &lt;code&gt;F5&lt;/code&gt; to run the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating an Android Device
&lt;/h3&gt;

&lt;p&gt;If you've not done any Xamarin work before, after a few seconds, you will see this screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tc7EO-Uw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/create-android-device.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tc7EO-Uw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/create-android-device.jpg" alt="Getting Started with Mobile Blazor Bindings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is because we don't currently have an Android device setup for the emulator to use. I'm not very familiar with Android devices so I've created the default device selected, Pixel 2 (+ Store). This seems to work really well, at least on my machine* 😋.&lt;/p&gt;

&lt;p&gt;Once you create your device, it will be downloaded and then you will be able to use it. This can take a good few minutes to complete.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running the App
&lt;/h3&gt;

&lt;p&gt;You will probably ended up back at Visual Studio, at least I did, but now the Start Debugging button should contain the name of the new device you've created. Hit &lt;code&gt;F5&lt;/code&gt; again and after a few moments you should see your new MBB app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--u0k4fEaY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/template-app-running.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u0k4fEaY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/template-app-running.png" alt="Getting Started with Mobile Blazor Bindings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Making Changes
&lt;/h3&gt;

&lt;p&gt;Let's make a simple change, well add in a button which updates the text to display "Hello, MBB!" instead of the default "Hello, World!". Currently, there is no hot reload available for MBB so we are going to have to stop debugging to make our changes.&lt;/p&gt;

&lt;p&gt;Once you've stopped debugging, open up the &lt;code&gt;HelloWorld.razor&lt;/code&gt; file, it should look like this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ContentView&amp;gt;
    &amp;lt;StackLayout Margin="new Thickness(20)"&amp;gt;

        &amp;lt;Label Text="Hello, World!"
               FontSize="40" /&amp;gt;

        &amp;lt;Counter /&amp;gt;

    &amp;lt;/StackLayout&amp;gt;
&amp;lt;/ContentView&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We're going to update the code to match the code below.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ContentView&amp;gt;
    &amp;lt;StackLayout Margin="new Thickness(20)"&amp;gt;

        &amp;lt;Label Text="@LabelText"
               FontSize="40" /&amp;gt;

        &amp;lt;Button Text="Update Message" OnClick="@(() =&amp;gt; LabelText = "Hello, MBB!")" /&amp;gt;

        &amp;lt;Counter /&amp;gt;

    &amp;lt;/StackLayout&amp;gt;
&amp;lt;/ContentView&amp;gt;

@code {

    public string LabelText { get; set; } = "Hello, World!";

}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Instead of the &lt;code&gt;Label&lt;/code&gt; text being hardcoded, it's now using the &lt;code&gt;WelcomeMessage&lt;/code&gt; property. When we click the &lt;code&gt;Button&lt;/code&gt; we're updating the value of &lt;code&gt;WelcomeMessage&lt;/code&gt; to be "&lt;em&gt;Hello, MBB!&lt;/em&gt;".&lt;/p&gt;

&lt;p&gt;Press &lt;code&gt;F5&lt;/code&gt; to run the updated app, when you click on &lt;em&gt;Update Message&lt;/em&gt; you should see the new message displayed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--obVolOTv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/template-app-updated.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--obVolOTv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/template-app-updated.png" alt="Getting Started with Mobile Blazor Bindings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations, you've just created, modified and run your first Mobile Blazor Bindings application!&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this post I have introduced Mobile Blazor Bindings. We started off by covering what MBB is, why we might choose to try it out and what components are available. We also talked about MBB in relation to Xamarin and how it complements the existing Xamarin platform.&lt;/p&gt;

&lt;p&gt;We then moved on to setting up a machine to use MBB, covering the workloads required by Visual Studio and Visual Studio for Mac. How to install the template for MBB and improve the performance of the Android device emulator by enabling Windows Hypervisor Platform.&lt;/p&gt;

&lt;p&gt;Finally, we created a new MBB app and ran it on an Android device emulator. We then made a simple change to the app, adding in a button which updated the default message displayed.&lt;/p&gt;

&lt;p&gt;I hope I've piqued you interest in Mobile Blazor Bindings. Next time I'm going to delve deeper by building out a more complex app.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>blazor</category>
      <category>xamarinforms</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Working with Query Strings in Blazor</title>
      <dc:creator>Chris Sainty</dc:creator>
      <pubDate>Wed, 25 Mar 2020 12:51:20 +0000</pubDate>
      <link>https://dev.to/chrissainty/working-with-query-strings-in-blazor-88a</link>
      <guid>https://dev.to/chrissainty/working-with-query-strings-in-blazor-88a</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VV-ol_52--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/working-with-query-strings-in-blazor.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VV-ol_52--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/working-with-query-strings-in-blazor.jpg" alt="Working with Query Strings in Blazor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this post I'm going to be taking a look at query strings and specifically how we can work with them in Blazor, because at this point in time, Blazor doesn't give us any tools out of the box. In fact, Blazor pretty much ignores them.&lt;/p&gt;

&lt;p&gt;We're going to start off by covering what query strings are and why we'd want to use them over route parameters. Then we'll get into some code and I'll show you a couple of options which should make working with them in your Blazor applications much easier.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Example Code:&lt;/strong&gt; A sample project to accompany this blog post can be found on &lt;a href="https://github.com/chrissainty/WorkingWithQueryStringsInBlazor"&gt;GitHub&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What are query strings?
&lt;/h2&gt;

&lt;p&gt;Query strings are essentially an instance or collection of key value pairs encoded into a URL. Below is an example of what a query string looks like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysite.com/about?name=Chris&amp;amp;favouritecolor=orange

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The start of a query string is separated from the rest of the URL by a &lt;code&gt;?&lt;/code&gt;. Then comes the key value pairs, each key and value is separated by a &lt;code&gt;=&lt;/code&gt;. If there's more than one pair a &lt;code&gt;&amp;amp;&lt;/code&gt; is used to separate them.&lt;/p&gt;

&lt;p&gt;In the example above, the query string contains two pairs, &lt;code&gt;name&lt;/code&gt; with a value of &lt;code&gt;Chris&lt;/code&gt; and &lt;code&gt;favouritecolour&lt;/code&gt; with a value of &lt;code&gt;orange&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One of the original use cases for query strings was to hold form data. When a form was submitted the field names and their values were encoded into the URL as query string values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use them over route parameters?
&lt;/h2&gt;

&lt;p&gt;A good question, for me, query strings provide a more flexibility over route parameters when it comes to optional values. Having optional parameters in a route can be a real pain if not impossible, in my experience at least. A good example of this is when using filters on a list page.&lt;/p&gt;

&lt;p&gt;Let's pretend we have a page listing cars (&lt;code&gt;/carsearch&lt;/code&gt;) and we offer the user the ability to filter that list by &lt;em&gt;make&lt;/em&gt;, &lt;em&gt;model&lt;/em&gt;, and &lt;em&gt;colour&lt;/em&gt;. If we wanted to use route parameters we'd have to use multiple route templates.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@page "/carsearch"
@page "/carsearch/{make}"
@page "/carsearch/{make}/{model}"
@page "/carsearch/{make}/{model}/{colour}"

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The problem is what happens if the user only selected &lt;em&gt;make&lt;/em&gt; and &lt;em&gt;colour&lt;/em&gt;? The route would look like this &lt;code&gt;/carsearch/ford/blue&lt;/code&gt;. Now we have a problem, the router is going to find a match with the 3rd template we've defined, &lt;code&gt;@page "/carsearch/{make}/{model}"&lt;/code&gt;. So we'd be trying to find all cars with a &lt;em&gt;make&lt;/em&gt; of &lt;code&gt;ford&lt;/code&gt; and a &lt;em&gt;model&lt;/em&gt; of &lt;code&gt;blue&lt;/code&gt;, oh dear.&lt;/p&gt;

&lt;p&gt;Now, we could work round this but using defaults for the various filters but it would be much simplier to use query strings instead.&lt;/p&gt;

&lt;p&gt;Query strings don't care about order of values, or even if a value is present or not, we don't even need to define them in a route template. Which means we can go back to using a single route template for our car search page.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@page "/carsearch"

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And when the user wants to filter we can just add the selected criteria to the URL using query strings.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/carsearch?make=ford&amp;amp;colour=blue

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The only problem now is how do we actually get hold of and use the values in our query string?&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing WebUtilites
&lt;/h2&gt;

&lt;p&gt;There is a library called &lt;code&gt;Microsoft.AspNetCore.WebUtilities&lt;/code&gt; which contains a fantastic helpers for dealing with query strings. It will chop up a query string for us and allow us to retrieve values in a straightforward way, meaning we don't have to get into loads of string manipulation.&lt;/p&gt;

&lt;p&gt;We're going to update the Counter page in the default template to look for a query string which sets the initial count for the counter. So given the url &lt;code&gt;/counter?initialCount=10&lt;/code&gt;, we'd expect the counter to start at 10. Here's how we can achieve that.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@page "/counter"
@inject NavigationManager NavManager

&amp;lt;h1&amp;gt;Counter&amp;lt;/h1&amp;gt;

&amp;lt;p&amp;gt;Current count: @currentCount&amp;lt;/p&amp;gt;

&amp;lt;button class="btn btn-primary" @onclick="IncrementCount"&amp;gt;Click me&amp;lt;/button&amp;gt;

@code {
    int currentCount = 0;

    protected override void OnInitialized()
    {
        var uri = NavManager.ToAbsoluteUri(NavManager.Uri);
        if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("initialCount", out var _initialCount))
        {
            currentCount = Convert.ToInt32(_initialCount);
        }
    }

    void IncrementCount()
    {
        currentCount++;
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can inject the &lt;code&gt;NavigationManager&lt;/code&gt; which gives us access to the current URI. Once we have that, we can pass the query string (&lt;code&gt;uri.Query&lt;/code&gt;) to the &lt;code&gt;WebUtilities&lt;/code&gt; helper and ask for the value of &lt;code&gt;initialCount&lt;/code&gt;. The last thing we need to do is convert the value of &lt;code&gt;initialCount&lt;/code&gt; to an &lt;code&gt;int&lt;/code&gt; as all values are returned as &lt;code&gt;string&lt;/code&gt;s by the helper.&lt;/p&gt;

&lt;p&gt;That wasn't actually too bad and if we just needed to do this on one page then we're now sorted. However, if we needed to use query strings in multiple places in our app this becomes a lot of boilerplate to have kicking around. So let's make this better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving to an Extension Method
&lt;/h2&gt;

&lt;p&gt;We can encapsulate all this functionality into a extension method on the &lt;code&gt;NavigationManager&lt;/code&gt; class. This should make working with query strings all over our app trivial going forward. Here's the code.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static class NavigationManagerExtensions
{
    public static bool TryGetQueryString&amp;lt;T&amp;gt;(this NavigationManager navManager, string key, out T value)
    {
        var uri = navManager.ToAbsoluteUri(navManager.Uri);

        if (QueryHelpers.ParseQuery(uri.Query).TryGetValue(key, out var valueFromQueryString))
        {
            if (typeof(T) == typeof(int) &amp;amp;&amp;amp; int.TryParse(valueFromQueryString, out var valueAsInt))
            {
                value = (T)(object)valueAsInt;
                return true;
            }

            if (typeof(T) == typeof(string))
            {
                value = (T)(object)valueFromQueryString.ToString();
                return true;
            }

            if (typeof(T) == typeof(decimal) &amp;amp;&amp;amp; decimal.TryParse(valueFromQueryString, out var valueAsDecimal))
            {
                value = (T)(object)valueAsDecimal;
                return true;
            }
        }

        value = default;
        return false;
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A lot of the code above is the same as we just saw, except I've used some generics to allow the caller to specify the type they want the requested value to be converted to. I've then added a some checks to covert values to &lt;code&gt;string&lt;/code&gt; &lt;code&gt;int&lt;/code&gt; or &lt;code&gt;decimal&lt;/code&gt; you could add whatever other ones you wish.&lt;/p&gt;

&lt;p&gt;If we refactor our counter page to use our new extension method this is what we end up with.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@page "/counter"
@inject NavigationManager NavManager

&amp;lt;h1&amp;gt;Counter&amp;lt;/h1&amp;gt;

&amp;lt;p&amp;gt;Current count: @currentCount&amp;lt;/p&amp;gt;

&amp;lt;button class="btn btn-primary" @onclick="IncrementCount"&amp;gt;Click me&amp;lt;/button&amp;gt;

@code {
    int currentCount = 0;

    protected override void OnInitialized()
    {
        NavManager.TryGetQueryString&amp;lt;int&amp;gt;("initialCount", out currentCount);
    }

    void IncrementCount()
    {
        currentCount++;
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That now looks much cleaner and we've got all our query string code in one place which is great for maintainability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dealing with updates to query string values
&lt;/h2&gt;

&lt;p&gt;One last scenario I want to cover is how to react to updates in query string values. Lets add a few links to our counter page which set the counter to different initial values, say 10, 20 and 30.&lt;/p&gt;

&lt;p&gt;The problem we have no is that when we click any of these links Blazor isn't going to call the &lt;code&gt;OnInitialized&lt;/code&gt; life cycle method again as we are already on the correct componet for the route. So how can we react to the new query string value? It turns out the &lt;code&gt;NavigationManager.LocationChanged&lt;/code&gt; event still fires, so we can setup a handler for that event which will retrieve the new values.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@page "/counter"
@inject NavigationManager NavManager

&amp;lt;h1&amp;gt;Counter&amp;lt;/h1&amp;gt;

&amp;lt;p&amp;gt;Current count: @currentCount&amp;lt;/p&amp;gt;

&amp;lt;button class="btn btn-primary" @onclick="IncrementCount"&amp;gt;Click me&amp;lt;/button&amp;gt;

&amp;lt;hr /&amp;gt;

&amp;lt;a href="/Counter?initialCount=10"&amp;gt;Start counter at 10.&amp;lt;/a&amp;gt; |
&amp;lt;a href="/Counter?initialCount=20"&amp;gt;Start counter at 20.&amp;lt;/a&amp;gt; |
&amp;lt;a href="/Counter?initialCount=30"&amp;gt;Start counter at 30.&amp;lt;/a&amp;gt;

@code {
    int currentCount = 0;

    protected override void OnInitialized()
    {
        GetQueryStringValues();
        NavManager.LocationChanged += (o, e) =&amp;gt; 
        {
            GetQueryStringValues();
            StateHasChanged();
        };
    }

    void GetQueryStringValues()
    {
        NavManager.TryGetQueryString&amp;lt;int&amp;gt;("initialCount", out currentCount);
    }

    void IncrementCount()
    {
        currentCount++;
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I think that wraps things up. We can now easily access query string values from any of our components both on initial load and when the URL is updated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this post I talked about working with query strings in Blazor. I started off by describing what query strings are and why you would choose to use them over route parameters.&lt;/p&gt;

&lt;p&gt;I then suggested some options on how to achieve this in Blazor. I started off with a simple solution based on the &lt;code&gt;Microsoft.AspNetCore.WebUtilities&lt;/code&gt; library. I then developed that into an extension method for the &lt;code&gt;NavigationManager&lt;/code&gt; class to avoid code duplication and ease use and maintainability.&lt;/p&gt;

</description>
      <category>blazor</category>
      <category>csharp</category>
      <category>dotnet</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Integrating Tailwind CSS with Blazor using Gulp - Part 2</title>
      <dc:creator>Chris Sainty</dc:creator>
      <pubDate>Tue, 03 Mar 2020 09:46:25 +0000</pubDate>
      <link>https://dev.to/chrissainty/integrating-tailwind-css-with-blazor-using-gulp-part-2-435i</link>
      <guid>https://dev.to/chrissainty/integrating-tailwind-css-with-blazor-using-gulp-part-2-435i</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cAyMFGN7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/integrating-tailwindcss-blazor-part2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cAyMFGN7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/integrating-tailwindcss-blazor-part2.jpg" alt="Integrating Tailwind CSS with Blazor using Gulp - Part 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last time, I &lt;a href="https://dev.to/chrissainty/integrating-tailwind-css-with-blazor-using-gulp-part-1-4k6g"&gt;introduced Tailwind CSS&lt;/a&gt; and showed how you can get it up and running with Blazor. This time I'm going to go a little deeper and show how you can customise and configure Tailwind for your application, optimise the final CSS, as well as how to integrate it all into a CI pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customising Tailwind
&lt;/h2&gt;

&lt;p&gt;I mentioned in part 1, it's possible to custom Tailwind to your specific needs. The default settings include, a set of colour palettes, fonts, padding and margin spacing, plus many more. And you can customise all of them via the &lt;code&gt;tailwind.config.js&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The file is split into three different sections, theme, variants and plugins. The theme section allows us to customise things like fonts, colour palettes, border widths, essentially anything related to the visual style of your site. The variants section allows you to configure the responsive and pseudo-class variants which are generated. These control the generation of classes which style things like hover and focus events. Finally, the plugins section allows you to add third party plugins which can generate even more CSS classes for your app. For a full breakdown of every option you can checkout the &lt;a href="https://tailwindcss.com/docs/configuration"&gt;fantastic official docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To see this in action we're going to add a custom colour on top of the default colour palettes. In the root of your app, create a new file called &lt;code&gt;tailwind.config.js&lt;/code&gt;, if you don't have one already, and paste in the following code.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  theme: {
    extend: {
      colors: {
        blazoredorange: '#ff6600'
      }
    }
  }
};

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The key here is the use of the &lt;code&gt;extend&lt;/code&gt; object, this tells Tailwind we want to ADD to the existing colours. If we had written the config like this instead.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  theme: {
    colors: {
      blazoredorange: '#ff6600'
    }
  }
};

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then we would be telling Tailwind to replace the existing colour palettes. It's worth noting that everything in Tailwinds configuration is optional, so you only need to include the things you want to override or extend.&lt;/p&gt;

&lt;p&gt;This file is automatically picked up by Tailwind during the build process so once you've finished adding your custom configuration, just rerun the gulp &lt;code&gt;css&lt;/code&gt; task to generate your new custom CSS. With the above configuration change we now get access to the following extra classes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;text-blazoredorange&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;border-blazoredorange&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bg-blazoredorange&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Optimising Your CSS
&lt;/h2&gt;

&lt;p&gt;One downside of Tailwind is that there are a lot of classes generated by default and you're potentially not using a lot of them in your application. This means that the size of your CSS file can be a bit large, relatively speaking. So what can we do about this?&lt;/p&gt;

&lt;h3&gt;
  
  
  Removing unused CSS with PurgeCSS
&lt;/h3&gt;

&lt;p&gt;There is a great plugin which solves this exact problem called &lt;a href="https://github.com/FullHuman/purgecss"&gt;PurgeCSS&lt;/a&gt;. It scans through your files and tries to determine what CSS classes you are using and then removes all the ones you don't. If we look back at the configuration we had for our Gulp file from part 1, it looks like this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const gulp = require('gulp');

gulp.task('css', () =&amp;gt; {
  const postcss = require('gulp-postcss');

  return gulp.src('./Styles/site.css')
    .pipe(postcss([
      require('precss'),
      require('tailwindcss'),
      require('autoprefixer')
    ]))
    .pipe(gulp.dest('./wwwroot/css/'));
});

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If we look at the size of the CSS file produced from this configuration, it's pretty large, 1073kb.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_Tvnof6y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/css-before-purge.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_Tvnof6y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/css-before-purge.png" alt="Integrating Tailwind CSS with Blazor using Gulp - Part 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is fine while we are working locally, in fact it's needed so we can have access to all those utility classes while we're developing. But once we've finished there will be a lot of unused classes that are now just taking up space. Let's update our config to use PurgeCSS and see what kind of saving we can make.&lt;/p&gt;

&lt;p&gt;First we need to install PurgeCSS using npm and the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev gulp-purgecss

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once that has completed we can update our &lt;code&gt;gulpfile.js&lt;/code&gt; to use PurgeCSS.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const gulp = require('gulp');

gulp.task('css', () =&amp;gt; {
  const postcss = require('gulp-postcss');
    const purgecss = require('gulp-purgecss');

  return gulp.src('./Styles/site.css')
    .pipe(postcss([
      require('precss'),
      require('tailwindcss'),
      require('autoprefixer')
    ]))
    .pipe(purgecss({ content: [' **/*.html', '** /*.razor'] }))
    .pipe(gulp.dest('./wwwroot/css/'));
});

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As part of the configuration for PurgeCSS I've passed in the types of files I want it to scan in order to look for CSS classes. I've specified it should look for any files ending in &lt;code&gt;.html&lt;/code&gt; or &lt;code&gt;.razor&lt;/code&gt; within my application. We can then run our Gulp task using the command &lt;code&gt;gulp css&lt;/code&gt;, as before, to regenerate our CSS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qcRwzuLB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/css-after-purge-better.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qcRwzuLB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/css-after-purge-better.png" alt="Integrating Tailwind CSS with Blazor using Gulp - Part 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wow! That's a pretty impressive size reduction! 1073kb down to 12kb. At this point it's worth checking your application to make sure everything still looks as it should, but so far I haven't found any issues.&lt;/p&gt;

&lt;p&gt;We could stop there but I think there are more savings to be had. After all, we've not even minimised the file. Let's do that next and see how we get on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Minimising CSS
&lt;/h3&gt;

&lt;p&gt;In order to minimise our CSS we need to install another plugin or two. First, we'll install &lt;a href="https://github.com/scniro/gulp-clean-css"&gt;CleanCSS&lt;/a&gt; which is going to do the minimising for us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt; npm install gulp-clean-css --save-dev

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Optionally, you can also install &lt;a href="https://github.com/gulp-sourcemaps/gulp-sourcemaps"&gt;Sourcemaps&lt;/a&gt; which will generate sourcemap files so you can debug your CSS once it's been minified. This isn't essential and I'll leave it up to you to decide if you want to include it or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install gulp-sourcemaps --save-dev

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With those plugins installed we can return to our &lt;code&gt;gulpfile&lt;/code&gt; and add some more configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const gulp = require('gulp');

gulp.task('css', () =&amp;gt; {
  const postcss = require('gulp-postcss');
  const purgecss = require('gulp-purgecss');
  const sourcemaps = require('gulp-sourcemaps');
  const cleanCSS = require('gulp-clean-css');

  return gulp.src('./Styles/site.css')
    .pipe(sourcemaps.init())
    .pipe(postcss([
      require('precss'),
      require('tailwindcss'),
      require('autoprefixer')
    ]))
    .pipe(purgecss({ content: [' **/*.html', '** /*.razor'] }))
    .pipe(cleanCSS({ level: 2 }))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('./wwwroot/css/'));
});

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The changes here are calling into CleanCSS once we have purged any unused classes. Then generating the sourcemap for the minified CSS file. If you don't want to create a sourcemap file then just leave those lines out of the config.&lt;/p&gt;

&lt;p&gt;Once you're done rerun your gulp task &lt;code&gt;gulp css&lt;/code&gt;, and let's see what the savings are.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9CKoTaTt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/css-after-purge-best.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9CKoTaTt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/03/css-after-purge-best.png" alt="Integrating Tailwind CSS with Blazor using Gulp - Part 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4KB! Now that is a pretty small file, I think you'll agree. I'm pretty happy with our work, we've taken the original file weighing in at 1073KB and we've managed to reduce it to only 4KB. This is great but we do have one problem.&lt;/p&gt;

&lt;p&gt;With the current configuration we only have one gulp task which produces our CSS and now it's producing a version which doesn't include all the utility classes we might need for future development. It would be much better to create two gulp tasks, one to use during development and one to use when we want to ship to production.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const gulp = require('gulp');
const postcss = require('gulp-postcss');
const sourcemaps = require('gulp-sourcemaps');
const cleanCSS = require('gulp-clean-css');
const purgecss = require('gulp-purgecss');

gulp.task('css:dev', () =&amp;gt; {
  return gulp.src('./Styles/site.css')
    .pipe(sourcemaps.init())
    .pipe(postcss([
      require('precss'),
      require('tailwindcss'),
      require('autoprefixer')
    ]))
    .pipe(gulp.dest('./wwwroot/css/'));
});

gulp.task('css:prod', () =&amp;gt; {
  return gulp.src('./Styles/site.css')
    .pipe(sourcemaps.init())
    .pipe(postcss([
      require('precss'),
      require('tailwindcss'),
      require('autoprefixer')
    ]))
    .pipe(purgecss({ content: [' **/*.html', '** /*.razor'] }))
    .pipe(cleanCSS({ level: 2 }))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('./wwwroot/css/'));
});

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here is the final configuration, we now have two gulp tasks, &lt;code&gt;css:dev&lt;/code&gt; and &lt;code&gt;css:prod&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By running the &lt;code&gt;css:dev&lt;/code&gt; task we can get the full CSS file with all of Tailwinds utility classes and any customisations we've made. The great thing is we only need to run this once to generate the initial CSS locally and then only again if we change any customisations.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;css:prod&lt;/code&gt; task is going to give us the super optimised version of our CSS to use in production. But we wouldn't want to run this locally, at least in an ideal world, it would be much better to use this in a CI pipeline when we deploy our application. So to finish things up, let look at how we can integrate all our work so far into a CI pipeline using Azure DevOps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using with TailwindCSS in a CI pipeline
&lt;/h2&gt;

&lt;p&gt;As our CSS file is compiled, we should check it into source control, we should have it be dynamically generated by our build process for each release. In order to do this we will need to install the tools we've been using locally via npm and then run our Gulp task to produce the production CSS.&lt;/p&gt;

&lt;p&gt;Unsurprisingly, there are already tasks available on Azure DevOps to do this. There is an &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/package/npm?view=azure-devops"&gt;npm task&lt;/a&gt; which will install all our npm packages and a &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/gulp?view=azure-devops"&gt;Gulp task&lt;/a&gt; we can use to build our CSS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;trigger:
- master

pool:
  vmImage: 'windows-latest'

variables:
  buildConfiguration: 'Release'

steps:
- task: UseDotNet@2
  displayName: 'Installing .NET Core SDK...'
  inputs:
    packageType: sdk
    version: 3.1.102
    installationPath: $(Agent.ToolsDirectory)/dotnet

- task: Npm@1
  displayName: 'Running NPM Install...'
  inputs:
    command: 'install'
    workingDir: 'MySite'

- task: gulp@1
  displayName: 'Running Gulp tasks'
  inputs:
    gulpFile: 'MySite/gulpfile.js' 
    targets: css:prod

- script: dotnet build --configuration $(buildConfiguration) MySite/MySite.csproj
  displayName: 'Building $(buildConfiguration)...'

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first task installs the latest .NET Core SDK. Then the npm install command is run via the npm task. Use the &lt;code&gt;workingDir&lt;/code&gt; setting to point to where your &lt;code&gt;package.json&lt;/code&gt; file lives in your project structure. Then the gulp &lt;code&gt;css:prod&lt;/code&gt; task is run before building the app.&lt;/p&gt;

&lt;p&gt;You can then publish your app where ever you wish and if you need some guidance on how to do that with Azure DevOps, I have a couple of posts which should help you out, &lt;a href="https://dev.to/chrissainty/building-blazor-apps-using-azure-pipelines-4984-temp-slug-5547047"&gt;here&lt;/a&gt; and &lt;a href="https://dev.to/chrissainty/deploying-blazor-apps-using-azure-pipelines-39fc-temp-slug-7250377"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;That bring us to an end. We now have Tailwind CSS integrated into our Blazor app allowing us to take advantage of its awesome utility based approach to styling UI.&lt;/p&gt;

&lt;p&gt;We have learned how to customise Tailwind using its extensive configuration options. We then saw how we can optimise the CSS we produced using PurgeCSS and CleanCSS to create the smallest file possible for a production scenario. Then we finished up by integrating Tailwind into a CI pipeline using Azure DevOps.&lt;/p&gt;

</description>
      <category>blazor</category>
      <category>tailwindcss</category>
      <category>dotnet</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Integrating Tailwind CSS with Blazor using Gulp - Part 1</title>
      <dc:creator>Chris Sainty</dc:creator>
      <pubDate>Tue, 18 Feb 2020 09:00:00 +0000</pubDate>
      <link>https://dev.to/chrissainty/integrating-tailwind-css-with-blazor-using-gulp-part-1-4k6g</link>
      <guid>https://dev.to/chrissainty/integrating-tailwind-css-with-blazor-using-gulp-part-1-4k6g</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gxy505tv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/02/Integrating-Tailwind-CSS-with-Blazor-using-Gulp-Part1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gxy505tv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/02/Integrating-Tailwind-CSS-with-Blazor-using-Gulp-Part1.jpg" alt="Integrating Tailwind CSS with Blazor using Gulp - Part 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've been a fan of &lt;a href="https://tailwindcss.com/"&gt;Tailwind CSS&lt;/a&gt; for quite some time now. It was created by &lt;a href="https://twitter.com/adamwathan"&gt;Adam Wathan&lt;/a&gt; and has been developed by &lt;a href="https://twitter.com/reinink"&gt;Jonathan Reinink&lt;/a&gt;, &lt;a href="https://twitter.com/davidhemphill"&gt;David Hemphill&lt;/a&gt;, and &lt;a href="https://twitter.com/steveschoger"&gt;Steve Schoger&lt;/a&gt;. I actually discovered Tailwind due to following Steve and his excellent &lt;a href="https://twitter.com/i/events/994601867987619840?lang=en"&gt;tweets on UI tips and tricks&lt;/a&gt;. In fact, if you are a developer with an interest in UI design, I couldn't recommend Steve's eBook, &lt;a href="https://refactoringui.com/"&gt;RefactoringUI&lt;/a&gt;, enough.&lt;/p&gt;

&lt;p&gt;Tailwind is a utility-first CSS framework, which means that instead of providing you with a set of premade UI components, which lead to every website looking the same, you are provided with a massive array of low-level utility classes that allow you to rapidly create custom designs with ease. Let me give you an example to illustrate.&lt;/p&gt;

&lt;p&gt;Let's look at styling a button with bootstrap first. We can define our button and apply the &lt;code&gt;btn&lt;/code&gt; and &lt;code&gt;btn-primary&lt;/code&gt; CSS classes as per the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button class="btn btn-primary"&amp;gt;Primary&amp;lt;/button&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will render a button that looks like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cOjVob56--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/02/bootstrap-button.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cOjVob56--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/02/bootstrap-button.png" alt="Integrating Tailwind CSS with Blazor using Gulp - Part 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we'll style a button using Tailwind.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button class="px-3 py-2 rounded-md bg-blue-600 text-white"&amp;gt;Primary&amp;lt;/button&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Which will render a button that looks like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--506IAlyi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/02/tailwind-button.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--506IAlyi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://chrissainty.com/content/images/2020/02/tailwind-button.png" alt="Integrating Tailwind CSS with Blazor using Gulp - Part 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see straight away, there are no tailored CSS classes in this version. The button is built up using multiple classes which each provide a single element of the styling. The &lt;code&gt;px&lt;/code&gt; and &lt;code&gt;py&lt;/code&gt; classes provide padding, &lt;code&gt;rounded-md&lt;/code&gt; rounds the corners of the button, &lt;code&gt;bg-blue-600&lt;/code&gt; colours the background and &lt;code&gt;text-white&lt;/code&gt; defines the text colour. You can checkout the full array of options on the &lt;a href="https://tailwindcss.com/docs"&gt;Tailwind docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You're probably thinking, but Chris, that's a lot more styles I have to apply to get the same result. I agree, but what you're getting in return is flexibility and the option to not have your site look like the thousands of others that use the same CSS framework. I appreciate this isn't something that interests everyone and there is nothing wrong with using frameworks like bootstrap, I have for years and it's awesome. But when you're trying to do something a little different Tailwind is your friend.&lt;/p&gt;

&lt;p&gt;Another huge benefit of using Tailwind is that you pretty much &lt;em&gt;never&lt;/em&gt; have to write any CSS classes yourself. As everything is composable using utility classes, you can create any look, any style from what's provided by the framework. Need your site to be responsive? No problem, Tailwind has &lt;a href="https://tailwindcss.com/docs/responsive-design"&gt;utilities for that&lt;/a&gt;. Need cool transitions? Tailwind has you &lt;a href="https://tailwindcss.com/docs/transition-property"&gt;covered there, too&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Tailwinds approach sits really well with component based UIs, such as Blazor. Building on the example above we could create a &lt;code&gt;PrimaryButton&lt;/code&gt; component which looks like this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- PrimaryButton.razor --&amp;gt;

&amp;lt;button class="px-3 py-2 rounded-md bg-blue-600 text-white"
        @onclick="HandleClick"&amp;gt;@Text&amp;lt;/button&amp;gt;

@code {
    [Parameter] public Action HandleClick { get; set; } 
    [Parameter] public string Text { get; set; } 
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We've now nicely encapsulated the styles for our primary button in a component. And if we need to update the styles later down the road, we can come to a single place to make the changes.&lt;/p&gt;

&lt;p&gt;It doesn't stop there either. Tailwind can also be customised. This is because Tailwind is more than just a CSS framework, it's written in &lt;a href="http://postcss.org/"&gt;PostCSS&lt;/a&gt; and can be configured to your needs. We're going to be covering how to do this in part 2.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating Tailwind with Blazor
&lt;/h2&gt;

&lt;p&gt;Hopefully, if you've gotten this far, I've convinced you to try Tailwind—or you're already a fan and just want to know how to use it with your Blazor app.&lt;/p&gt;

&lt;p&gt;In order to get the most out of Tailwind, we're going to be using some tools you may or may not be familiar with from the JavaScript ecosystem, &lt;a href="https://www.npmjs.com/"&gt;NPM&lt;/a&gt; and &lt;a href="https://gulpjs.com/"&gt;Gulp&lt;/a&gt;. If you're not familiar with these tools, I've added a link to each of them so you can have a read up on what they do.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing NodeJS to get NPM
&lt;/h3&gt;

&lt;p&gt;If you haven't already got NodeJS installed then you will need to do that first. This is because installing node installs NPM (Node Package Manager). Head over to the &lt;a href="https://nodejs.org/"&gt;Node site&lt;/a&gt; and grab the latest LTS version (12.16.0 at the time of writing). Run the installer, you should be able to accept all the defaults, just make sure that &lt;em&gt;npm package manager&lt;/em&gt; is selected.&lt;/p&gt;

&lt;p&gt;Once the installer is finished, open a terminal and type &lt;code&gt;npm -v&lt;/code&gt;. If you see a version number printed out then you're good to go.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Gulp and Tailwind via NPM
&lt;/h3&gt;

&lt;p&gt;The next thing we need to do is install the Gulp CLI globally, this will allow us to work with Gulp on the command line. At your terminal type &lt;code&gt;npm install gulp-cli -g&lt;/code&gt;. Once the install has completed we can turn our attention to our Blazor project.&lt;/p&gt;

&lt;p&gt;In the root of your Blazor app, add a new file called &lt;code&gt;package.json&lt;/code&gt; and then add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "devDependencies": {
    "gulp": "^4.0.2",
    "gulp-postcss": "^8.0.0",
    "precss": "^4.0.0",
    "tailwindcss": "^1.2.0",
    "autoprefixer": "^9.7.4"
  }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This tells NPM what packages to install for our project. We'll see how these are used a little later in when we configure Gulp.&lt;/p&gt;

&lt;p&gt;The next step is to setup our CSS file as per the Tailwinds docs. The way I do this is by creating a folder in the root of my app called &lt;code&gt;Styles&lt;/code&gt; and in there add a file called &lt;code&gt;site.css&lt;/code&gt; (you can name this file whatever you want). The reason this file is sitting outside of the &lt;code&gt;wwwroot&lt;/code&gt; folder is because it is it going to be processed to produce the final CSS file which will be outputted to the &lt;code&gt;wwwroot&lt;/code&gt; folder. Then add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@tailwind base;
@tailwind components;
@tailwind utilities;

#blazor-error-ui {
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The three lines at the top are all we need to add to get all of those awesome Tailwind utilities. When the file is processed, those three lines will be replaced with all the generated classes from Tailwind. You can also add any custom styles you want present in the final CSS file as well. I've made sure to keep the styling for the Blazor error messages which come in the default project template.&lt;/p&gt;

&lt;p&gt;The last part is to add another file to the root of the project called &lt;code&gt;gulpfile.js&lt;/code&gt;. This is where we are going to configure Gulp to build Tailwind for us. Add the following code, remember to update the filename if you didn't use &lt;code&gt;site.css&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const gulp = require('gulp');

gulp.task('css', () =&amp;gt; {
  const postcss = require('gulp-postcss');

  return gulp.src('./Styles/site.css')
    .pipe(postcss([
      require('precss'),
      require('tailwindcss'),
      require('autoprefixer')
    ]))
    .pipe(gulp.dest('./wwwroot/css/'));
});

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We're defining a single Gulp task called &lt;code&gt;css&lt;/code&gt;. It takes the &lt;code&gt;site.css&lt;/code&gt; we defined above as an input and then runs it though a plugin called &lt;code&gt;postcss&lt;/code&gt;. Essentially, this plugin builds all of those Tailwind utility classes. Once it's finished, the processed CSS is output into the &lt;code&gt;wwwroot/css&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;With all of the above in place, open a terminal and navigate to the root of the Blazor app, the same folder where the &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;gulpfile.js&lt;/code&gt; reside. Once there, run the following commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install
gulp css

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first command will install all the packages in the &lt;code&gt;package.json&lt;/code&gt; file we created earlier. Once that's finished, the second command executes the &lt;code&gt;css&lt;/code&gt; task we defined in our &lt;code&gt;gulpfile.js&lt;/code&gt;. If all has gone well you should see a new file, &lt;code&gt;site.css&lt;/code&gt; in your &lt;code&gt;wwwroot/css&lt;/code&gt; folder. All that's left to do is to reference the file in your apps &lt;code&gt;index.html&lt;/code&gt; or &lt;code&gt;_Host.cshtml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Congratulations! You can now go and start building your UI using the utility of Tailwind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this post, I've shown how to integrate the awesome, utility-first CSS framework, Tailwind CSS into your Blazor project. We started by looking at what makes Tailwind different to other CSS frameworks such as Bootstrap and reasons why we'd want to use it. We then looked at how we can integrate it with a Blazor application using NPM and Gulp.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post and if you didn't know about Tailwind before, that I've made you curious about it. Next time, we're going to go a little deeper down the rabbit hole. We'll look at how we can customise Tailwind using it's configuration system. As well as how we can optimise our outputted CSS by removing unused classes. To finish off we'll go through how to integrate Tailwind into a CI pipeline with Azure DevOps.&lt;/p&gt;

&lt;p&gt;I'm using Tailwind to build a new documentation site for the Blazored UI packages. So if you want to see this in a real world application then feel free to &lt;a href="https://github.com/Blazored/docs"&gt;check it out on GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>blazor</category>
      <category>tailwindcss</category>
      <category>dotnet</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
