MarkdownEditor and ui/start-confetti-button had no importers anywhere in the repo and both carried a different product's content: MarkdownEditor hardcoded https://app.pertento.ai/logo.png with alt="Pertento", and start-confetti-button spoke about 'the experiment' and 'Draft/Created' statuses. Translating either would have put feature words into ui.*, which D6 forbids — a shared namespace may not name a feature. todo/inputs-outside-forms named MarkdownEditor as deliberately-unwrapped, so that entry is updated rather than left pointing at a deleted file.
5.4 KiB
theme, heading, kind
| theme | heading | kind |
|---|---|---|
| inputs-outside-forms | Inputs outside forms (2026-08-19) — swept, fixed, closed | theme |
The "19 files" count in the previous version of this entry came from one grep
(components/ui/input) and was a starting point, not the answer. A wider sweep — bare <input> and
<textarea> too, across the platform and every installed plugin — found 87 files with a matching
element and no enclosing <form>. Three were false positives (the Input/Textarea primitives
themselves, and a DataTable test file). Of the remaining 84, 41 were fixed (real forms, single
fields with an obvious action, or multi-field editors) and 43 were left alone, almost all because
they're a search/filter box with nothing to submit.
Fixed — platform (24 files, one commit): CapabilityPage, ApifyConfig, ApiKeys,
DavAppPasswords, GoogleOAuthConfig, AIHarnessesSection (local-provider connect, its auth step,
and both API-key edit rows), OCRSection, SMTPSection (split into two independent forms — save vs.
send-test-email, since one form would have made Enter in the test-email field trigger Save),
STTSection, TTSSection, AppStoreDetail, ChatHeader, BackgroundJobDialog, QuestionActivity,
WebpageDialog, DirPickerModal, SessionRow, CommandHqCategories, FileItem, NewEntryDialog,
TaskRunnerModal (the Agentic and Pipeline ready phases), PreviewHeader, widgets/DailyGoals,
widgets/Pomodoro.
Fixed — plugins (17 files, one commit per plugin, each pushed to its own remote):
bitcoin-wallet (ChainSourceCard, RescanCard, WalletSettingsView), email (Compose,
EmailAccounts), invoices (DocumentEditor, RecordEditors, SendDocumentDialog), offscale
(NodesView — rename and tags fields), soulseek (SoulseekConnection), transmission
(ConnectionView, SettingsView, AddTorrentDialog, MoveTorrentDialog, RenameDialog,
TorrentOptionsDialog), vault (VaultPanel). jellyfin and music needed no changes.
Left alone — search/filter boxes with no submit action (the large majority of the 43): JobsPage,
SettingsPanel, SearchInput, sounds/Catalog, widgets/QuickNotes, Dashboards/DashboardListApp,
SystemMonitor/DockerView, FileBrowser* toolbar/header/view-container files, ChatHistory list
filters, invoices' six list views (CustomersListView, EstimatesListView, ExpensesListView,
InvoicesListView, ItemsListView, ReportsView, components.tsx), jellyfin (PlayerControls —
range sliders, not text fields — and SearchSection), music (MusicBrowser, MusicPlayerHost),
offscale (Cards, PolicyAssistant — already handles Enter/Shift+Enter correctly, PolicyView — a
textarea, never auto-submits), soulseek (SearchResults, SharesBrowser), transmission
(TorrentToolbar), FileViewer renderers (AudioRenderer/VideoRenderer — volume/seek sliders), and
the main chat composers (InputArea, ChatLauncher, SoulseekChat) — all textareas with their own
Enter-sends/Shift+Enter-newlines handling, where a <form> would add nothing and risks regressing that
handling.
Left alone — genuinely ambiguous, flagged rather than guessed:
TaskRunnerModal'sScriptRunnerready phase offers three simultaneously-visible, non-equivalent primary actions ("Run here" / "Queue" / "Run as job"); there's no single canonical action for Enter to trigger.Dashboards/DashboardPreview'sNamePanel(name + description) has its submit button in a different, independently-mounted panel (CreatePanel) elsewhere in the workspace layout tree — a<form>can't span two panels without restructuring the wizard.ColorPickerhas zero call sites anywhere in the repo right now; it is shaped to be embedded in a future caller's own form (uncontrolled inputs withnameattributes), so there's nothing to wrap yet.MarkdownEditorwas named here too and was deleted on 2026-08-23 during the localization pass — it had no call sites and hardcoded another product's logo URL.widgets/Weather'sLocationSetupis a live autocomplete with several result rows and no single obvious Enter target (which of N matches?).
Noticed, out of scope, not fixed:
ModelSelector's provider-picker button has notypeattribute — harmless today only because it currently sits outside every<form>; a landmine if that layout changes.MusicBrowser's filter input uses(e) =>instead of the houseevconvention — pre-existing, not touched since the file needed no fix.EmailList.tsx, and a few plugin files touched by this sweep (VaultPanel,ConnectionView,SoulseekConnection,ChainSourceCard), have pre-existingprettier --checkdrift outside the lines this pass touched — left as found, not reformatted, per "don't reformat what you're not fixing." Relatedly:prettier --writeon aplugins/<name>/…path silently no-ops when run from the platform root, because Prettier v3 respects the root.gitignoreand/plugins/*/is in it — it exits 0 with no diff and no error. Formatting a plugin file requires running prettier from inside that plugin's own directory (still resolves the platform's.prettierrcby walking up).- A few "Save"/"I've saved it"-style buttons (
ApiKeys,DavAppPasswords,DirPickerModal) have notypeattribute but currently sit outside any<form>, so it's harmless today — worth remembering if a future edit wraps that region.