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:
- 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.
- 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.
- 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.
- 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.


.png)
.png)
.png)
Comments
Post a Comment