Blazor Without the Bloat: Building “Power Inputs” with Plain HTML

 


When starting to build forms in Blazor, it's common to immediately reach for a third-party component library. Date pickers, masked inputs, sliders, validation UI, file upload widgets – the list goes on. While these libraries can be incredibly useful, they also come with tradeoffs: extra dependencies, styling constraints, larger downloads, and the need to learn a new component API that often duplicates what browsers already do well.

This post serves as a powerful reminder that modern HTML inputs are already "power controls." With Blazor, you can wire them up with minimal C# code while retaining all the benefits of native browser behavior. The result? Simple, fast, dependency-free UI that still feels modern and responsive.


The Core Idea: Let the Browser Do the Work

This approach demonstrates a wide range of input types using plain HTML, leveraging the browser's native capabilities:

  • type="email" for native email validation
  • type="url" for URL validation
  • type="date", type="time", type="datetime-local" for native pickers
  • type="range" for an instant slider
  • min, max, step, required, pattern, minlength, maxlength for built-in constraints
  • autocomplete, inputmode, capture, accept to significantly improve User Experience (especially on mobile devices)
  • type="file" via both <InputFile> and raw HTML

This strategy leans on standards the browser natively understands, rather than re-implementing them in .NET or wrapping them in complex component abstractions.




Blazor as the Glue: Bindings + Events, Not Widgets

The form utilizes an EditForm with:

  • Model="@Model" to centralize state management
  • OnSubmit="@HandleSubmit" to capture submission attempts
  • DataAnnotationsValidator + ValidationSummary to seamlessly integrate Blazor validation

Yet, the individual fields are predominantly plain HTML inputs augmented with @bind:

  • Text-ish fields: @bind="Model.Username", @bind="Model.Email", etc.
  • Numeric: @bind="Model.Quantity"
  • Range: @bind="Model.Volume" complemented by a live display: Value: @Model.Volume
  • Checkbox: @bind="Model.Subscribe"

This exemplifies a "low ceremony" style of Blazor development: keep the UI as simple HTML, and use Blazor primarily for state management and event handling.


Native HTML Validation + Blazor Validation (Together)

A crucial detail lies in the intelligent use of OnSubmit:

  • OnSubmit executes regardless of whether the form is valid.
  • The handler explicitly calls editContext.Validate() to determine what validation messages to display.

This means you benefit from both:

  • Browser-native validation constraints (required, minlength, pattern, etc.)
  • Blazor’s robust validation pipeline (managed via the EditContext)

You're not confined to a single validation strategy. You have the flexibility to choose what runs client-side and what runs server-side later, all without the need to replace UI components.




Modern Inputs That People Forget Exist

Here are a few highlights from the page that are often overlooked, yet provide significant functionality without needing third-party components:

  1. Mobile-friendly keyboards with inputmode Using inputmode="numeric" or inputmode="tel" is a small attribute that significantly improves the mobile user experience. No component library required.
  2. datalist for lightweight autocomplete Instead of pulling in an autocomplete component, HTML offers the list + datalist pattern. While not as feature-rich as a full searchable dropdown, it's often sufficient for many cases and incredibly efficient.
  3. month and week input types If you're building credit card expiry/monthly reporting or timesheets, type="month" and type="week" natively solve common problems with date/time controls.
  4. File inputs with accept and capture The example showcases:
    • <InputFile> for proper Blazor file handling (IBrowserFile)
    • Raw <input type="file"> with multiple, accept="image/*", and capture="environment" for mobile camera integration.

This illustrates a pragmatic difference: use <InputFile> when you need actual file streams, and stick to plain HTML when you only need basic UX or a placeholder hook.




Reusability Without a Component Library: Your Own “Power Inputs”

The natural next step is to transform repeated patterns into reusable components, all without adopting a heavy third-party suite.

In your page, many cards follow a consistent structure:

  • A label/title
  • An <input ... @bind="..."> element
  • A short hint/description
  • An optional inline “current value” display

You can extract these into small, focused components that still render plain HTML, for example:

  • TextInput.razor (wrapping type="text" + common attributes)
  • NumberInput.razor (handling min/max/step)
  • RangeInput.razor (for sliders + value readouts)
  • FileInput.razor (wrapping <InputFile> + accept + displayed filename)
  • InputCard.razor (a layout wrapper used by every example)

This strategy keeps your "design system" within your own repository: versioned with your application, styled precisely how you desire, and only as complex as your specific needs dictate.


Why This Strategy Works (Especially for Blazor)

This approach offers several compelling advantages:

  • Fewer dependencies: No external component packages means fewer breaking changes, simpler transitive updates, and less maintenance overhead.
  • Better performance characteristics: Plain HTML generally translates to less JavaScript, lighter render trees, and smaller download sizes, leading to faster loading times and a snappier user experience.
  • Standards-based behavior: You inherit accessibility and expected behaviors directly from the platform, rather than hoping a component library has meticulously implemented every detail.
  • Easier debugging: When something goes awry, you inspect an actual <input> element in the browser's developer tools—not a complex, opaque component abstraction.



Where Third-Party Components Still Make Sense

This approach isn't "anti-library"; rather, it advocates for "using libraries intentionally."

Embrace third-party components when you truly encounter a need that native HTML and simple Blazor bindings cannot elegantly address. This might include:

  • Complex data grids with advanced filtering and sorting
  • Virtualization-heavy UI for displaying massive datasets
  • Rich text editors with sophisticated formatting capabilities
  • Highly customized date/time experiences that go far beyond what the browser offers
  • Advanced masking or formatting requirements for specific input types

However, for a vast majority of forms, browser-native inputs combined with Blazor's binding capabilities will cover 80–90% of what most applications require.


Wrap-up: Blazor + Plain HTML is a Productive Baseline

This post demonstrates a highly practical and effective pattern:

  • Utilize native HTML inputs as your default choice.
  • Enhance UX with modern attributes like autocomplete, inputmode, pattern, and capture.
  • Leverage Blazor for state management (@bind) and event processing (OnSubmit, OnChange).
  • Extract small, reusable components when repetition emerges, without committing to a full third-party UI suite.

By adopting this strategy, you can build performant, maintainable, and dependency-free Blazor applications that feel both modern and professional.


[source code]

 

Comments

Popular posts from this blog

Customizing PWA Manifest and Icons for a Polished User Experience 🚀

Offline-First Strategy with Blazor PWAs: A Complete Guide 🚀

Yes, Blazor Server can scale!