Fix FormItemLayout usages for a11y (#49761)

Follow up of #49637. Usages that impacted tests were fixed in the
previous PR. This PR fixes the other usages so that label are correctly
linked to their inputs.

No visual changes

## How to test

1. Design system: [Form
examples](https://design-system-git-fix-form-item-layout-usages-supabase.vercel.app/design-system/docs/ui-patterns/forms):
moved `FormControl` around the `SelectTrigger` so that the label is
linked to the button (It's actually done like this in the [Select Form
example](https://design-system-git-fix-form-item-layout-usages-supabase.vercel.app/design-system/docs/components/select#form)
and Radix recommend targeting the button too in their
[documentation](https://www.radix-ui.com/primitives/docs/components/select#labelling))
2. [Access
tokens](https://studio-staging-463111oii-supabase.vercel.app/dashboard/account/tokens):
updated usage to fallback on generated ids and fixed the select just
like _1_
3. [New TOTP
factor](https://studio-staging-463111oii-supabase.vercel.app/dashboard/account/security):
updated usage to fallback on generated ids
4. _Studio/Database/Extensions_
(`https://studio-staging-463111oii-supabase.vercel.app/dashboard/project/[PROJECT]/database/extensions`):
updated the extension enabling modal to fallback on generated ids
5. _Studio/Integrations/Vault
(`https://studio-staging-463111oii-supabase.vercel.app/dashboard/project/[PROJECT]/integrations/vault/secrets`):
updated the secret edition modal to fallback on generated ids
6.
_Studio/Observability(`https://studio-staging-463111oii-supabase.vercel.app/dashboard/project/[PROJECT]/observability`):
updated the report creation and edition modals to fallback on generated
ids
7. _Studio/SQL
Editor(`https://studio-staging-463111oii-supabase.vercel.app/dashboard/project/[PROJECT]/sql/new`):
updated the query renaming modal to fallback on generated ids
8.
_Studio/Storage/Analytics(`https://studio-staging-463111oii-supabase.vercel.app/dashboard/project/[PROJECT]/storage/analytics`):
updated the table creation sheet to fallback on generated ids (you must
have a bucket first)
9.
_Studio/Workers(`https://studio-staging-463111oii-supabase.vercel.app/dashboard/project/[PROJECT]/workers`):
updated the worker creation modal to fallback on generated ids (you must
have a bucket first)
10. Updated
[Signup](https://studio-staging-463111oii-supabase.vercel.app/dashboard/sign-up?returnTo=%2Fnew),
[Signin](https://studio-staging-463111oii-supabase.vercel.app/dashboard/sign-in)
and [SSO
Signin](https://studio-staging-463111oii-supabase.vercel.app/dashboard/sign-in-sso)
forms to fallback on generated ids

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Improvements**
- Standardized form field presentation across access tokens,
authentication, reports, integrations, database extensions, SQL editor,
storage, and worker deployment workflows.
- Updated password fields and visibility toggles for more consistent
input behavior.
- Refined token expiration selection, verification code entry, and
dropdown layouts.
- Preserved existing labels, validation, options, and form functionality
while simplifying the interface structure.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Gildas Garcia authored and GitHub committed 2026-09-01 15:22:55 +02:00
1 parent 8db7368ccf
commit 3146650a5a
15 files changed
+86 -115

No files matched your search

@@ -580,18 +580,18 @@ export default function FormPatternsPageLayout() {
label="Select (Dropdown)"
description="Single selection from a list of options"
>
<FormControl>
<Select value={field.value} onValueChange={field.onChange}>
<Select value={field.value} onValueChange={field.onChange}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select an option" />
</SelectTrigger>
<SelectContent>
<SelectItem value="us-east-1">US East (N. Virginia)</SelectItem>
<SelectItem value="us-west-2">US West (Oregon)</SelectItem>
<SelectItem value="eu-west-1">EU West (Ireland)</SelectItem>
</SelectContent>
</Select>
</FormControl>
</FormControl>
<SelectContent>
<SelectItem value="us-east-1">US East (N. Virginia)</SelectItem>
<SelectItem value="us-west-2">US West (Oregon)</SelectItem>
<SelectItem value="eu-west-1">EU West (Ireland)</SelectItem>
</SelectContent>
</Select>
</FormItemLayout>
)}
/>
@@ -573,18 +573,18 @@ export default function FormPatternsSidePanel() {
label="Select (Dropdown)"
description="Single selection from a list of options"
>
<FormControl className="col-span-6">
<Select value={field.value} onValueChange={field.onChange}>
<Select value={field.value} onValueChange={field.onChange}>
<FormControl className="col-span-6">
<SelectTrigger>
<SelectValue placeholder="Select an option" />
</SelectTrigger>
<SelectContent>
<SelectItem value="us-east-1">US East (N. Virginia)</SelectItem>
<SelectItem value="us-west-2">US West (Oregon)</SelectItem>
<SelectItem value="eu-west-1">EU West (Ireland)</SelectItem>
</SelectContent>
</Select>
</FormControl>
</FormControl>
<SelectContent>
<SelectItem value="us-east-1">US East (N. Virginia)</SelectItem>
<SelectItem value="us-west-2">US West (Oregon)</SelectItem>
<SelectItem value="eu-west-1">EU West (Ireland)</SelectItem>
</SelectContent>
</Select>
</FormItemLayout>
)}
/>
@@ -183,13 +183,9 @@ export const NewTokenDialog = ({
name="tokenName"
control={form.control}
render={({ field }) => (
<FormItemLayout name="tokenName" label="Name">
<FormItemLayout label="Name">
<FormControl>
<Input
id="tokenName"
{...field}
placeholder="Provide a name for your token"
/>
<Input {...field} placeholder="Provide a name for your token" />
</FormControl>
</FormItemLayout>
)}
@@ -199,24 +195,24 @@ export const NewTokenDialog = ({
name="expiresAt"
control={form.control}
render={({ field }) => (
<FormItemLayout name="expiresAt" label="Expires in">
<FormItemLayout label="Expires in">
<div className="flex gap-2">
<FormControl className="grow">
<Select value={field.value} onValueChange={handleExpiryChange}>
<Select value={field.value} onValueChange={handleExpiryChange}>
<FormControl className="grow">
<SelectTrigger>
<SelectValue placeholder="Expires at" />
</SelectTrigger>
<SelectContent>
{Object.values(EXPIRES_AT_OPTIONS).map(
(option: { value: string; label: string }) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
)
)}
</SelectContent>
</Select>
</FormControl>
</FormControl>
<SelectContent>
{Object.values(EXPIRES_AT_OPTIONS).map(
(option: { value: string; label: string }) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
)
)}
</SelectContent>
</Select>
{isCustomExpiry && (
<DatePicker
selectsRange={false}
@@ -59,7 +59,7 @@ export const TokenDetails = ({ control, setValue }: TokenDetailsProps) => {
name="tokenName"
control={control}
render={({ field }) => (
<FormItemLayout name="tokenName" label="Name" layout="flex-row-reverse">
<FormItemLayout label="Name" layout="flex-row-reverse">
<FormControl>
<Input {...field} placeholder="e.g. CI deploy token" />
</FormControl>
@@ -245,15 +245,9 @@ const SecondStep = ({
name="code"
control={form.control}
render={({ field }) => (
<FormItemLayout name="code" label="Authentication code">
<FormItemLayout label="Authentication code">
<FormControl>
<Input
id="code"
autoFocus
{...field}
placeholder="XXXXXX"
className="font-mono"
/>
<Input autoFocus {...field} placeholder="XXXXXX" className="font-mono" />
</FormControl>
</FormItemLayout>
)}
@@ -239,7 +239,7 @@ export const EnableExtensionModal = ({
name="name"
control={form.control}
render={({ field }) => (
<FormItemLayout name="name" label="Schema name">
<FormItemLayout label="Schema name">
<FormControl>
<Input {...field} />
</FormControl>
@@ -144,7 +144,7 @@ export const EditSecretModal = () => {
name="name"
control={form.control}
render={({ field }) => (
<FormItemLayout name="name" label="Name">
<FormItemLayout label="Name">
<FormControl>
<Input {...field} />
</FormControl>
@@ -156,11 +156,7 @@ export const EditSecretModal = () => {
name="description"
control={form.control}
render={({ field }) => (
<FormItemLayout
name="description"
label="Description"
labelOptional="Optional"
>
<FormItemLayout label="Description" labelOptional="Optional">
<FormControl>
<Input {...field} data-lpignore="true" />
</FormControl>
@@ -172,7 +168,7 @@ export const EditSecretModal = () => {
name="secret"
control={form.control}
render={({ field }) => (
<FormItemLayout name="secret" label="Secret value">
<FormItemLayout label="Secret value">
<div className="relative">
<FormControl>
<Textarea
@@ -126,9 +126,9 @@ export const CreateReportModal = ({ visible, onCancel, afterSubmit }: CreateRepo
control={form.control}
name="name"
render={({ field }) => (
<FormItemLayout name="name" layout="vertical" label="Name">
<FormItemLayout layout="vertical" label="Name">
<FormControl>
<Input {...field} id="name" />
<Input {...field} />
</FormControl>
</FormItemLayout>
)}
@@ -139,11 +139,10 @@ export const CreateReportModal = ({ visible, onCancel, afterSubmit }: CreateRepo
control={form.control}
name="description"
render={({ field }) => (
<FormItemLayout name="description" layout="vertical" label="Description">
<FormItemLayout layout="vertical" label="Description">
<FormControl>
<Textarea
{...field}
id="description"
rows={4}
placeholder="Describe your custom report"
className="resize-none"
@@ -103,9 +103,9 @@ export const UpdateCustomReportModal = ({
control={form.control}
name="name"
render={({ field }) => (
<FormItemLayout name="name" layout="vertical" label="Name">
<FormItemLayout layout="vertical" label="Name">
<FormControl>
<Input {...field} id="name" />
<Input {...field} />
</FormControl>
</FormItemLayout>
)}
@@ -116,11 +116,10 @@ export const UpdateCustomReportModal = ({
control={form.control}
name="description"
render={({ field }) => (
<FormItemLayout name="description" layout="vertical" label="Description">
<FormItemLayout layout="vertical" label="Description">
<FormControl>
<Textarea
{...field}
id="description"
rows={4}
placeholder="Describe your custom report"
className="resize-none"
@@ -169,7 +169,7 @@ const RenameQueryForm = ({ snippet, onCancel, onComplete }: RenameQueryFormProps
control={form.control}
name="name"
render={({ field }) => (
<FormItemLayout name="name" layout="vertical" label="Name">
<FormItemLayout layout="vertical" label="Name">
<FormControl>
<Input {...field} />
</FormControl>
@@ -209,11 +209,10 @@ const RenameQueryForm = ({ snippet, onCancel, onComplete }: RenameQueryFormProps
control={form.control}
name="description"
render={({ field }) => (
<FormItemLayout name="description" layout="vertical" label="Description">
<FormItemLayout layout="vertical" label="Description">
<FormControl>
<Textarea
{...field}
id="description"
rows={4}
placeholder="Describe query"
className="resize-none"
@@ -133,10 +133,9 @@ export const SignInForm = () => {
name="email"
control={form.control}
render={({ field }) => (
<FormItemLayout name="email" label="Email">
<FormItemLayout label="Email">
<FormControl>
<Input
id="email"
type="email"
autoComplete="email"
{...field}
@@ -154,11 +153,10 @@ export const SignInForm = () => {
name="password"
control={form.control}
render={({ field }) => (
<FormItemLayout name="password" label="Password">
<FormControl>
<div className="relative">
<FormItemLayout label="Password">
<div className="relative">
<FormControl>
<Input
id="password"
type={passwordHidden ? 'password' : 'text'}
autoComplete="current-password"
{...field}
@@ -166,17 +164,17 @@ export const SignInForm = () => {
disabled={isSubmitting}
className="pr-10"
/>
<Button
variant="default"
title={passwordHidden ? `Show password` : `Hide password`}
aria-label={passwordHidden ? `Show password` : `Hide password`}
className="absolute right-1 top-1 px-1.5"
icon={passwordHidden ? <Eye /> : <EyeOff />}
disabled={isSubmitting}
onClick={() => setPasswordHidden((prev) => !prev)}
/>
</div>
</FormControl>
</FormControl>
<Button
variant="default"
title={passwordHidden ? `Show password` : `Hide password`}
aria-label={passwordHidden ? `Show password` : `Hide password`}
className="absolute right-1 top-1 px-1.5"
icon={passwordHidden ? <Eye /> : <EyeOff />}
disabled={isSubmitting}
onClick={() => setPasswordHidden((prev) => !prev)}
/>
</div>
</FormItemLayout>
)}
/>
@@ -88,15 +88,9 @@ export const SignInSSOForm = () => {
name="email"
control={form.control}
render={({ field }) => (
<FormItemLayout name="email" label="Email">
<FormItemLayout label="Email">
<FormControl>
<Input
id="email"
type="email"
autoComplete="email"
{...field}
placeholder="gavin@hooli.com"
/>
<Input type="email" autoComplete="email" {...field} placeholder="gavin@hooli.com" />
</FormControl>
</FormItemLayout>
)}
@@ -159,10 +159,9 @@ export const SignUpForm = ({ onSuccess }: { onSuccess?: () => void }) => {
name="email"
control={form.control}
render={({ field }) => (
<FormItemLayout name="email" label="Email">
<FormItemLayout label="Email">
<FormControl>
<Input
id="email"
autoComplete="email"
disabled={isSubmitting}
{...field}
@@ -178,11 +177,10 @@ export const SignUpForm = ({ onSuccess }: { onSuccess?: () => void }) => {
name="password"
control={form.control}
render={({ field }) => (
<FormItemLayout name="password" label="Password">
<FormControl>
<div className="relative">
<FormItemLayout label="Password">
<div className="relative">
<FormControl>
<Input
id="password"
type={passwordHidden ? 'password' : 'text'}
autoComplete="new-password"
placeholder="&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;"
@@ -190,17 +188,17 @@ export const SignUpForm = ({ onSuccess }: { onSuccess?: () => void }) => {
onFocus={() => setShowConditions(true)}
disabled={isSubmitting}
/>
<Button
variant="default"
title={passwordHidden ? `Show password` : `Hide password`}
aria-label={passwordHidden ? `Show password` : `Hide password`}
className="absolute right-1 top-1 px-1.5"
icon={passwordHidden ? <Eye /> : <EyeOff />}
disabled={isSubmitting}
onClick={() => setPasswordHidden((prev) => !prev)}
/>
</div>
</FormControl>
</FormControl>
<Button
variant="default"
title={passwordHidden ? `Show password` : `Hide password`}
aria-label={passwordHidden ? `Show password` : `Hide password`}
className="absolute right-1 top-1 px-1.5"
icon={passwordHidden ? <Eye /> : <EyeOff />}
disabled={isSubmitting}
onClick={() => setPasswordHidden((prev) => !prev)}
/>
</div>
</FormItemLayout>
)}
/>
@@ -193,7 +193,7 @@ export const CreateTableSheet = ({ open, onOpenChange }: CreateTableSheetProps)
name="newNamespace"
control={form.control}
render={({ field }) => (
<FormItemLayout name="newNamespace" label="Name of new namespace">
<FormItemLayout label="Name of new namespace">
<FormControl>
<Input {...field} placeholder="Provide a name for your new namespace" />
</FormControl>
@@ -211,7 +211,7 @@ export const CreateTableSheet = ({ open, onOpenChange }: CreateTableSheetProps)
name="name"
control={form.control}
render={({ field }) => (
<FormItemLayout name="name" label="Name of table">
<FormItemLayout label="Name of table">
<FormControl>
<Input {...field} placeholder="Provide a name for your new table" />
</FormControl>
@@ -102,7 +102,7 @@ export const DeployWorkerDialog = ({ open, onOpenChange }: DeployWorkerDialogPro
control={form.control}
name="name"
render={({ field }) => (
<FormItemLayout name="name" label="Name">
<FormItemLayout label="Name">
<FormControl>
<Input {...field} placeholder="my-worker" />
</FormControl>
@@ -114,7 +114,7 @@ export const DeployWorkerDialog = ({ open, onOpenChange }: DeployWorkerDialogPro
control={form.control}
name="runtime"
render={({ field }) => (
<FormItemLayout name="runtime" label="Runtime">
<FormItemLayout label="Runtime">
<Select value={field.value} onValueChange={field.onChange}>
<FormControl>
<SelectTrigger>
@@ -138,7 +138,6 @@ export const DeployWorkerDialog = ({ open, onOpenChange }: DeployWorkerDialogPro
name="size"
render={({ field }) => (
<FormItemLayout
name="size"
label="Size"
description="Fixed at deploy time and cannot be changed later"
>
@@ -165,7 +164,6 @@ export const DeployWorkerDialog = ({ open, onOpenChange }: DeployWorkerDialogPro
name="access"
render={({ field }) => (
<FormItemLayout
name="access"
label="Access"
description="Public workers accept requests with a publishable key"
>
@@ -191,7 +189,7 @@ export const DeployWorkerDialog = ({ open, onOpenChange }: DeployWorkerDialogPro
control={form.control}
name="instances"
render={({ field }) => (
<FormItemLayout name="instances" label="Instances" description="1 to 10">
<FormItemLayout label="Instances" description="1 to 10">
<FormControl>
<Input
{...field}