mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
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:
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="••••••••"
|
||||
@@ -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>
|
||||
)}
|
||||
/>
|
||||
|
||||
+2
-2
@@ -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}
|
||||
|
||||
Reference in new issue
Block a user