fix: use visually-hidden clip pattern for file inputs
Some checks failed
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m25s
CI / deploy (push) Has been cancelled
CI / deploy-feature (push) Has been cancelled
CI / docker (push) Has been cancelled

The opacity:0 approach caused the native "Choose File" button to
appear in the accessibility tree and compete for clicks. The clip
pattern properly hides the input while keeping it functional for
programmatic .click().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-08 21:23:05 +02:00
parent 19da9b9f9f
commit 18ffbea9db

View File

@@ -303,7 +303,7 @@ function CreateAppView({ environments, selectedEnv }: { environments: Environmen
<span className={styles.configLabel}>Application JAR</span> <span className={styles.configLabel}>Application JAR</span>
<div className={styles.fileRow}> <div className={styles.fileRow}>
<input ref={fileInputRef} type="file" accept=".jar" <input ref={fileInputRef} type="file" accept=".jar"
style={{ position: 'absolute', width: 0, height: 0, opacity: 0, overflow: 'hidden' }} style={{ position: 'absolute', width: 1, height: 1, margin: -1, padding: 0, overflow: 'hidden', clip: 'rect(0,0,0,0)', border: 0 }}
onChange={(e) => setFile(e.target.files?.[0] ?? null)} /> onChange={(e) => setFile(e.target.files?.[0] ?? null)} />
<Button size="sm" variant="secondary" type="button" onClick={() => fileInputRef.current?.click()} disabled={busy}> <Button size="sm" variant="secondary" type="button" onClick={() => fileInputRef.current?.click()} disabled={busy}>
{file ? 'Change file' : 'Select JAR'} {file ? 'Change file' : 'Select JAR'}
@@ -541,7 +541,7 @@ function AppDetailView({ appId, environments, selectedEnv }: { appId: string; en
</div> </div>
<div className={styles.detailActions}> <div className={styles.detailActions}>
<input ref={fileInputRef} type="file" accept=".jar" <input ref={fileInputRef} type="file" accept=".jar"
style={{ position: 'absolute', width: 0, height: 0, opacity: 0, overflow: 'hidden' }} style={{ position: 'absolute', width: 1, height: 1, margin: -1, padding: 0, overflow: 'hidden', clip: 'rect(0,0,0,0)', border: 0 }}
onChange={handleUpload} /> onChange={handleUpload} />
<Button size="sm" variant="primary" type="button" onClick={() => fileInputRef.current?.click()} loading={uploadJar.isPending}>Upload JAR</Button> <Button size="sm" variant="primary" type="button" onClick={() => fileInputRef.current?.click()} loading={uploadJar.isPending}>Upload JAR</Button>
<Button size="sm" variant="danger" onClick={() => setDeleteConfirm(true)}>Delete App</Button> <Button size="sm" variant="danger" onClick={() => setDeleteConfirm(true)}>Delete App</Button>