From 71160ba8304cfbc9fbe519c8ce5181d2cf2d50fb Mon Sep 17 00:00:00 2001 From: Leendert de Borst Date: Mon, 8 Jun 2026 13:33:40 +0200 Subject: [PATCH] Switch Blazor input bind to oninput instead of onchange (#2147) --- .../Auth/Components/InputTextField.razor | 16 +++++----- .../AliasVault.Client/Auth/Pages/Login.razor | 2 +- .../Main/Components/TotpCodes/TotpCodes.razor | 4 +-- .../Settings/ImportExport/ResetVault.razor | 4 +-- .../Settings/Security/DeleteAccount.razor | 4 +-- .../Pages/Settings/Security/Enable2Fa.razor | 2 +- .../Shared/Components/InputTextOnInput.razor | 30 +++++++++++++++++++ apps/server/AliasVault.Client/_Imports.razor | 1 + 8 files changed, 48 insertions(+), 15 deletions(-) create mode 100644 apps/server/AliasVault.Client/Shared/Components/InputTextOnInput.razor diff --git a/apps/server/AliasVault.Client/Auth/Components/InputTextField.razor b/apps/server/AliasVault.Client/Auth/Components/InputTextField.razor index a85ed93dd..84619e2e2 100644 --- a/apps/server/AliasVault.Client/Auth/Components/InputTextField.razor +++ b/apps/server/AliasVault.Client/Auth/Components/InputTextField.razor @@ -1,12 +1,14 @@ @using System.Linq.Expressions - +@* Thin styled wrapper around InputTextOnInput so the auth forms get consistent styling without repeating the long + Tailwind class list. The actual bind-on-input logic lives in InputTextOnInput. *@ + @code { /// diff --git a/apps/server/AliasVault.Client/Auth/Pages/Login.razor b/apps/server/AliasVault.Client/Auth/Pages/Login.razor index 2076c8e26..7efa7230e 100644 --- a/apps/server/AliasVault.Client/Auth/Pages/Login.razor +++ b/apps/server/AliasVault.Client/Auth/Pages/Login.razor @@ -68,7 +68,7 @@ else if (_showLoginWithRecoveryCodeStep)
- +
diff --git a/apps/server/AliasVault.Client/Main/Components/TotpCodes/TotpCodes.razor b/apps/server/AliasVault.Client/Main/Components/TotpCodes/TotpCodes.razor index 40e5f8ac1..b4a193ada 100644 --- a/apps/server/AliasVault.Client/Main/Components/TotpCodes/TotpCodes.razor +++ b/apps/server/AliasVault.Client/Main/Components/TotpCodes/TotpCodes.razor @@ -55,12 +55,12 @@

@Localizer["TotpInstructions"]

- +
- +
diff --git a/apps/server/AliasVault.Client/Main/Pages/Settings/ImportExport/ResetVault.razor b/apps/server/AliasVault.Client/Main/Pages/Settings/ImportExport/ResetVault.razor index 2df4f361f..42cbfde94 100644 --- a/apps/server/AliasVault.Client/Main/Pages/Settings/ImportExport/ResetVault.razor +++ b/apps/server/AliasVault.Client/Main/Pages/Settings/ImportExport/ResetVault.razor @@ -33,7 +33,7 @@
- +
@@ -59,7 +59,7 @@
- +
diff --git a/apps/server/AliasVault.Client/Main/Pages/Settings/Security/DeleteAccount.razor b/apps/server/AliasVault.Client/Main/Pages/Settings/Security/DeleteAccount.razor index 9211e3772..5b5b56f61 100644 --- a/apps/server/AliasVault.Client/Main/Pages/Settings/Security/DeleteAccount.razor +++ b/apps/server/AliasVault.Client/Main/Pages/Settings/Security/DeleteAccount.razor @@ -38,7 +38,7 @@
- +
@@ -66,7 +66,7 @@
- +
diff --git a/apps/server/AliasVault.Client/Main/Pages/Settings/Security/Enable2Fa.razor b/apps/server/AliasVault.Client/Main/Pages/Settings/Security/Enable2Fa.razor index 0ff591f0a..22766eead 100644 --- a/apps/server/AliasVault.Client/Main/Pages/Settings/Security/Enable2Fa.razor +++ b/apps/server/AliasVault.Client/Main/Pages/Settings/Security/Enable2Fa.razor @@ -38,7 +38,7 @@ else
- diff --git a/apps/server/AliasVault.Client/Shared/Components/InputTextOnInput.razor b/apps/server/AliasVault.Client/Shared/Components/InputTextOnInput.razor new file mode 100644 index 000000000..24a9bc480 --- /dev/null +++ b/apps/server/AliasVault.Client/Shared/Components/InputTextOnInput.razor @@ -0,0 +1,30 @@ +@using System.Diagnostics.CodeAnalysis +@using Microsoft.AspNetCore.Components.Forms +@inherits InputBase + +@* A drop-in replacement for Blazor's built-in that updates the bound value on the `oninput` event + instead of `onchange`. The built-in component only commits the value on blur, which means programmatically filled + values (e.g. password-manager autofill) that never receive a blur are not bound, which can result in a + a "required" validation error on submit. *@ + + +@code { + /// + /// Commits the new value to the EditContext on every input event so autofilled values are captured immediately. + /// + private void OnInput(ChangeEventArgs e) + { + CurrentValueAsString = e.Value?.ToString(); + } + + /// + protected override bool TryParseValueFromString(string? value, out string? result, [NotNullWhen(false)] out string? validationErrorMessage) + { + result = value; + validationErrorMessage = null; + return true; + } +} diff --git a/apps/server/AliasVault.Client/_Imports.razor b/apps/server/AliasVault.Client/_Imports.razor index bafbb7ab1..9e59e5eee 100644 --- a/apps/server/AliasVault.Client/_Imports.razor +++ b/apps/server/AliasVault.Client/_Imports.razor @@ -28,6 +28,7 @@ @using AliasVault.Client.Services.Auth @using AliasVault.Client.Services.Database @using AliasVault.Client.Services.JsInterop; +@using AliasVault.Client.Shared.Components @using AliasVault.RazorComponents @using AliasVault.RazorComponents.Alerts @using AliasVault.RazorComponents.Buttons