Skip to content

Commit aeafa7c

Browse files
fix(clerk-js,localizations,types): Add min and max lengths to username field error (#4771)
1 parent 5c5f1db commit aeafa7c

File tree

8 files changed

+64
-5
lines changed

8 files changed

+64
-5
lines changed

.changeset/cold-tomatoes-float.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@clerk/localizations': patch
3+
'@clerk/clerk-js': patch
4+
'@clerk/types': patch
5+
---
6+
7+
Added min and max length username settings to username field error.

packages/clerk-js/src/core/resources/UserSettings.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
SamlSettings,
99
SignInData,
1010
SignUpData,
11+
UsernameSettingsData,
1112
UserSettingsJSON,
1213
UserSettingsJSONSnapshot,
1314
UserSettingsResource,
@@ -19,6 +20,9 @@ import { BaseResource } from './internal';
1920
const defaultMaxPasswordLength = 72;
2021
const defaultMinPasswordLength = 8;
2122

23+
const defaultMinUsernameLength = 4;
24+
const defaultMaxUsernameLength = 64;
25+
2226
export type Actions = {
2327
create_organization: boolean;
2428
delete_self: boolean;
@@ -40,6 +44,7 @@ export class UserSettings extends BaseResource implements UserSettingsResource {
4044
signUp!: SignUpData;
4145
passwordSettings!: PasswordSettingsData;
4246
passkeySettings!: PasskeySettingsData;
47+
usernameSettings!: UsernameSettingsData;
4348

4449
socialProviderStrategies: OAuthStrategy[] = [];
4550
authenticatableSocialStrategies: OAuthStrategy[] = [];
@@ -85,6 +90,11 @@ export class UserSettings extends BaseResource implements UserSettingsResource {
8590
? defaultMaxPasswordLength
8691
: Math.min(data?.password_settings?.max_length, defaultMaxPasswordLength),
8792
};
93+
this.usernameSettings = {
94+
...data.username_settings,
95+
min_length: Math.max(data?.username_settings?.min_length, defaultMinUsernameLength),
96+
max_length: Math.min(data?.username_settings?.max_length, defaultMaxUsernameLength),
97+
};
8898
this.passkeySettings = data.passkey_settings;
8999
this.socialProviderStrategies = this.getSocialProviderStrategies(data.social);
90100
this.authenticatableSocialStrategies = this.getAuthenticatableSocialStrategies(data.social);

packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { useCardState } from '../../elements/contexts';
2020
import { useLoadingStatus } from '../../hooks';
2121
import { useRouter } from '../../router';
2222
import type { FormControlState } from '../../utils';
23-
import { buildRequest, createPasswordError, handleError, useFormControl } from '../../utils';
23+
import { buildRequest, createPasswordError, createUsernameError, handleError, useFormControl } from '../../utils';
2424
import { SignUpForm } from './SignUpForm';
2525
import type { ActiveIdentifier } from './signUpFormHelpers';
2626
import { determineActiveFields, emailOrPhone, getInitialActiveIdentifier, showFormFields } from './signUpFormHelpers';
@@ -52,7 +52,7 @@ function _SignUpStart(): JSX.Element {
5252
const [missingRequirementsWithTicket, setMissingRequirementsWithTicket] = React.useState(false);
5353

5454
const {
55-
userSettings: { passwordSettings },
55+
userSettings: { passwordSettings, usernameSettings },
5656
} = useEnvironment();
5757

5858
const { mode } = userSettings.signUp;
@@ -78,6 +78,7 @@ function _SignUpStart(): JSX.Element {
7878
label: localizationKeys('formFieldLabel__username'),
7979
placeholder: localizationKeys('formFieldInputPlaceholder__username'),
8080
transformer: value => value.trim(),
81+
buildErrorMessage: errors => createUsernameError(errors, { t, locale, usernameSettings }),
8182
}),
8283
phoneNumber: useFormControl('phoneNumber', signUp.phoneNumber || initialValues.phoneNumber || '', {
8384
type: 'tel',

packages/clerk-js/src/ui/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ export * from './createCustomPages';
2323
export * from './ExternalElementMounter';
2424
export * from './colorOptionToHslaScale';
2525
export * from './createCustomMenuItems';
26+
export * from './usernameUtils';

packages/clerk-js/src/ui/utils/useFormControl.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ type Options = {
3232
buildErrorMessage?: (err: ClerkAPIError[]) => ClerkAPIError | string | undefined;
3333
radioOptions?: never;
3434
}
35+
| {
36+
label: string | LocalizationKey;
37+
type: Extract<HTMLInputTypeAttribute, 'text'>;
38+
validatePassword?: never;
39+
buildErrorMessage?: (err: ClerkAPIError[]) => ClerkAPIError | string | undefined;
40+
radioOptions?: never;
41+
}
3542
| {
3643
validatePassword?: never;
3744
buildErrorMessage?: never;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { ClerkAPIError, UsernameSettingsData } from '@clerk/types';
2+
3+
import { type LocalizationKey, localizationKeys } from '../localization';
4+
5+
type LocalizationConfigProps = {
6+
t: (localizationKey: LocalizationKey | string | undefined) => string;
7+
locale: string;
8+
usernameSettings: Pick<UsernameSettingsData, 'max_length' | 'min_length'>;
9+
};
10+
11+
export const createUsernameError = (errors: ClerkAPIError[], localizationConfig: LocalizationConfigProps) => {
12+
const { t, usernameSettings } = localizationConfig;
13+
14+
if (!localizationConfig) {
15+
return errors[0].longMessage;
16+
}
17+
18+
const msg = t(
19+
localizationKeys('unstable__errors.form_username_invalid_length', {
20+
min_length: usernameSettings.min_length,
21+
max_length: usernameSettings.max_length,
22+
}),
23+
);
24+
25+
return msg;
26+
};

packages/localizations/src/en-US.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ export const enUS: LocalizationResource = {
5050
formFieldInputPlaceholder__organizationDomainEmailAddress: '[email protected]',
5151
formFieldInputPlaceholder__organizationName: 'Organization name',
5252
formFieldInputPlaceholder__organizationSlug: 'my-org',
53-
formFieldInputPlaceholder__username: undefined,
5453
formFieldInputPlaceholder__password: 'Enter your password',
5554
formFieldInputPlaceholder__phoneNumber: 'Enter your phone number',
55+
formFieldInputPlaceholder__username: undefined,
5656
formFieldLabel__automaticInvitations: 'Enable automatic invitations for this domain',
5757
formFieldLabel__backupCode: 'Backup code',
5858
formFieldLabel__confirmDeletion: 'Confirmation',
@@ -439,6 +439,7 @@ export const enUS: LocalizationResource = {
439439
detailsLabel: 'We need to verify your identity before resetting your password.',
440440
},
441441
start: {
442+
__experimental_titleCombined: 'Continue to {{applicationName}}',
442443
actionLink: 'Sign up',
443444
actionLink__join_waitlist: 'Join waitlist',
444445
actionLink__use_email: 'Use email',
@@ -450,7 +451,6 @@ export const enUS: LocalizationResource = {
450451
actionText__join_waitlist: 'Want early access?',
451452
subtitle: 'Welcome back! Please sign in to continue',
452453
title: 'Sign in to {{applicationName}}',
453-
__experimental_titleCombined: 'Continue to {{applicationName}}',
454454
},
455455
totpMfa: {
456456
formTitle: 'Verification code',
@@ -566,7 +566,7 @@ export const enUS: LocalizationResource = {
566566
form_password_validation_failed: 'Incorrect Password',
567567
form_username_invalid_character:
568568
'Your username contains invalid characters. Please use only letters, numbers, and underscores.',
569-
form_username_invalid_length: 'Your username must be between 3 and 20 characters long.',
569+
form_username_invalid_length: 'Your username must be between {{min_length}} and {{max_length}} characters long.',
570570
identification_deletion_failed: 'You cannot delete your last identification.',
571571
not_allowed_access:
572572
'You do not have permission to access this page. Please contact support if you believe this is an error.',

packages/types/src/userSettings.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ export type PasswordSettingsData = {
7272
min_zxcvbn_strength: number;
7373
};
7474

75+
export type UsernameSettingsData = {
76+
min_length: number;
77+
max_length: number;
78+
};
79+
7580
export type PasskeySettingsData = {
7681
allow_autofill: boolean;
7782
show_sign_in_button: boolean;
@@ -119,6 +124,7 @@ export interface UserSettingsJSON extends ClerkResourceJSON {
119124
sign_up: SignUpData;
120125
password_settings: PasswordSettingsData;
121126
passkey_settings: PasskeySettingsData;
127+
username_settings: UsernameSettingsData;
122128
}
123129

124130
export interface UserSettingsResource extends ClerkResource {
@@ -136,6 +142,7 @@ export interface UserSettingsResource extends ClerkResource {
136142
signIn: SignInData;
137143
signUp: SignUpData;
138144
passwordSettings: PasswordSettingsData;
145+
usernameSettings: UsernameSettingsData;
139146
passkeySettings: PasskeySettingsData;
140147
socialProviderStrategies: OAuthStrategy[];
141148
authenticatableSocialStrategies: OAuthStrategy[];

0 commit comments

Comments
 (0)