From fa2e2c6ba20f5b80a4abc3fefb9c8dd556d1595d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Tue, 30 Jun 2026 18:32:35 +0200 Subject: [PATCH] fix(ui): tell Bitwarden to skip config and secret fields The Input and Textarea primitives already opted config and secret fields out of 1Password and LastPass autofill (data-1p-ignore / data-lpignore) whenever autocomplete was off, but Bitwarden had no opt-out hint anywhere, so it kept offering to fill and save API keys, tokens and integration URLs. Emit data-bwignore alongside the existing hints, which covers every field flowing through the primitives. Pin explicit autocomplete on the change-password dialog so genuine credentials still autofill, and add the ignore hints to the export passphrase and the few new-password admin config fields that opt in directly. --- src/components/admin/glitchtip-section.tsx | 2 ++ src/components/admin/umami-section.tsx | 2 ++ src/components/admin/web-push-vapid-section.tsx | 3 +++ src/components/settings/account-section/index.tsx | 3 +++ src/components/settings/export-section.tsx | 3 +++ src/components/ui/__tests__/input.test.tsx | 3 +++ src/components/ui/__tests__/textarea.test.tsx | 2 ++ src/components/ui/input.tsx | 11 +++++++++-- src/components/ui/textarea.tsx | 5 ++++- 9 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/components/admin/glitchtip-section.tsx b/src/components/admin/glitchtip-section.tsx index 2640f58e8..c14a18cc8 100644 --- a/src/components/admin/glitchtip-section.tsx +++ b/src/components/admin/glitchtip-section.tsx @@ -102,6 +102,7 @@ export function GlitchtipSection() { spellCheck={false} data-lpignore="true" data-1p-ignore="true" + data-bwignore="true" disabled={updateSettings.isPending} /> @@ -121,6 +122,7 @@ export function GlitchtipSection() { spellCheck={false} data-lpignore="true" data-1p-ignore="true" + data-bwignore="true" disabled={updateSettings.isPending} /> diff --git a/src/components/admin/umami-section.tsx b/src/components/admin/umami-section.tsx index 27f7954a7..6a92dd0a8 100644 --- a/src/components/admin/umami-section.tsx +++ b/src/components/admin/umami-section.tsx @@ -105,6 +105,7 @@ export function UmamiSection() { spellCheck={false} data-lpignore="true" data-1p-ignore="true" + data-bwignore="true" disabled={updateSettings.isPending} /> @@ -122,6 +123,7 @@ export function UmamiSection() { spellCheck={false} data-lpignore="true" data-1p-ignore="true" + data-bwignore="true" disabled={updateSettings.isPending} /> diff --git a/src/components/admin/web-push-vapid-section.tsx b/src/components/admin/web-push-vapid-section.tsx index d67d49bc6..16092aa65 100644 --- a/src/components/admin/web-push-vapid-section.tsx +++ b/src/components/admin/web-push-vapid-section.tsx @@ -144,6 +144,7 @@ export function WebPushVapidSection() { spellCheck={false} data-lpignore="true" data-1p-ignore="true" + data-bwignore="true" disabled={updateSettings.isPending} /> @@ -163,6 +164,7 @@ export function WebPushVapidSection() { spellCheck={false} data-lpignore="true" data-1p-ignore="true" + data-bwignore="true" disabled={updateSettings.isPending} /> @@ -182,6 +184,7 @@ export function WebPushVapidSection() { spellCheck={false} data-lpignore="true" data-1p-ignore="true" + data-bwignore="true" disabled={updateSettings.isPending} /> diff --git a/src/components/settings/account-section/index.tsx b/src/components/settings/account-section/index.tsx index 1ca9531b9..a6249cdb9 100644 --- a/src/components/settings/account-section/index.tsx +++ b/src/components/settings/account-section/index.tsx @@ -527,6 +527,7 @@ export function AccountSection() { setCurrentPassword(e.target.value)} /> @@ -537,6 +538,7 @@ export function AccountSection() { setNewPassword(e.target.value)} /> @@ -547,6 +549,7 @@ export function AccountSection() { setConfirmPassword(e.target.value)} /> diff --git a/src/components/settings/export-section.tsx b/src/components/settings/export-section.tsx index 08582fbb0..e84567a89 100644 --- a/src/components/settings/export-section.tsx +++ b/src/components/settings/export-section.tsx @@ -522,6 +522,9 @@ function FullBackupCard() { "settings.sections.export.cards.fullBackup.passphrasePlaceholder", )} autoComplete="new-password" + data-lpignore="true" + data-1p-ignore="true" + data-bwignore="true" className="h-9 text-sm" />

diff --git a/src/components/ui/__tests__/input.test.tsx b/src/components/ui/__tests__/input.test.tsx index fe23398d5..8931b90c6 100644 --- a/src/components/ui/__tests__/input.test.tsx +++ b/src/components/ui/__tests__/input.test.tsx @@ -9,6 +9,7 @@ describe("", () => { expect(html).toContain('autoComplete="off"'); expect(html).toContain('data-lpignore="true"'); expect(html).toContain('data-1p-ignore="true"'); + expect(html).toContain('data-bwignore="true"'); }); it("respects an explicit autoComplete value and drops the ignore attrs", () => { @@ -18,6 +19,7 @@ describe("", () => { expect(html).toContain('autoComplete="email"'); expect(html).not.toContain('data-lpignore="true"'); expect(html).not.toContain('data-1p-ignore="true"'); + expect(html).not.toContain('data-bwignore="true"'); }); it("explicit autoComplete=username keeps password manager active for login flows", () => { @@ -27,6 +29,7 @@ describe("", () => { expect(html).toContain('autoComplete="username"'); expect(html).not.toContain("lpignore"); expect(html).not.toContain("1p-ignore"); + expect(html).not.toContain("bwignore"); }); it("derives inputMode=decimal from type=number", () => { diff --git a/src/components/ui/__tests__/textarea.test.tsx b/src/components/ui/__tests__/textarea.test.tsx index 23fe3c323..6535a0b02 100644 --- a/src/components/ui/__tests__/textarea.test.tsx +++ b/src/components/ui/__tests__/textarea.test.tsx @@ -21,6 +21,7 @@ describe("