Sign Up Block
The SignUp Component is a fully customizable and accessible sign-up form built with React, TypeScript, and MUI. It provides a complete user registration interface with modern design patterns, form validation using react-hook-form, terms acceptance, and flexible customization options.
🚀 Installation
npm install @nodeblocks/frontend-signup-block@0.4.0
📖 Usage
import {SignUp} from '@nodeblocks/frontend-signup-block';
- Basic Usage
- Advanced Usage
function BasicSignUp() { return ( <SignUp onChange={(setError, getValues, clearErrors) => { const values = getValues(); if (!values.email) { setError('email', {message: 'Email is required', type: 'required'}); } else { clearErrors('email'); } }} onSubmit={formData => { console.log('Form submitted:', formData); }} > <SignUp.SignUpTitle>Create Your Account</SignUp.SignUpTitle> <SignUp.EmailField label="Email Address" placeholder="Enter your email" /> <SignUp.PasswordField label="Password" placeholder="Enter your password" /> <SignUp.TermsOfUse name="agreesUserAgreement" label="I agree to the terms of use" /> <SignUp.PrivacyPolicy name="agreesPrivacyPolicy" label="I agree to the privacy policy" /> <SignUp.SignUpButton>Sign Up</SignUp.SignUpButton> <SignUp.GotoSignIn> <span> Already have an account? <a href="#signin">Sign In</a> </span> </SignUp.GotoSignIn> </SignUp> ); }
function AdvancedSignUp() { return ( <SignUp onChange={(setError, getValues, clearErrors) => { const values = getValues(); if (!values.email) { setError('email', {message: 'メールアドレスが必要です', type: 'required'}); } else { clearErrors('email'); } if (!values.password) { setError('password', {message: 'パスワードが必要です', type: 'required'}); } else { clearErrors('password'); } }} onSubmit={formData => { console.log('新規登録:', formData); }} sx={{ maxWidth: '500px', margin: '0 auto', background: 'linear-gradient(145deg, #f8fafc 0%, #f1f5f9 100%)', borderRadius: '20px', border: '1px solid #e2e8f0', }} > {({defaultBlocks, defaultBlockOrder}) => ({ blocks: { ...defaultBlocks, signUpTitle: { ...defaultBlocks.signUpTitle, props: { ...defaultBlocks.signUpTitle.props, sx: { background: 'linear-gradient(135deg, #0f172a 0%, #1e293b 100%)', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent', backgroundClip: 'text', fontSize: '2rem', fontWeight: 'bold', textAlign: 'center', marginBottom: '8px', }, children: '企業アカウント作成', }, }, emailField: { ...defaultBlocks.emailField, props: { ...defaultBlocks.emailField.props, label: 'メールアドレス', placeholder: '例: user@company.com', sx: { '& .MuiOutlinedInput-root': { borderRadius: '10px', }, }, }, }, passwordField: { ...defaultBlocks.passwordField, props: { ...defaultBlocks.passwordField.props, label: 'パスワード', placeholder: '8文字以上の安全なパスワード', sx: { '& .MuiOutlinedInput-root': { borderRadius: '10px', }, }, }, }, termsOfUse: { ...defaultBlocks.termsOfUse, props: { ...defaultBlocks.termsOfUse.props, name: 'agreesUserAgreement', label: ( <span style={{color: '#64748b', fontSize: '14px'}}> <a href="#terms" style={{color: '#3b82f6', textDecoration: 'none', fontWeight: '500'}}> 利用規約 </a> に同意します </span> ), }, }, privacyPolicy: { ...defaultBlocks.privacyPolicy, props: { ...defaultBlocks.privacyPolicy.props, name: 'agreesPrivacyPolicy', label: ( <span style={{color: '#64748b', fontSize: '14px'}}> <a href="#privacy" style={{color: '#3b82f6', textDecoration: 'none', fontWeight: '500'}}> プライバシーポリシー </a> に同意します </span> ), }, }, signUpButton: { ...defaultBlocks.signUpButton, props: { ...defaultBlocks.signUpButton.props, sx: { background: '#3b82f6', borderRadius: '10px', py: 1.5, '&:hover': {background: '#2563eb'}, }, children: 'アカウントを作成', }, }, gotoSignIn: { ...defaultBlocks.gotoSignIn, props: { ...defaultBlocks.gotoSignIn.props, sx: { textAlign: 'center', }, children: ( <span style={{color: '#64748b', fontSize: '14px'}}> 既にアカウントをお持ちの方は{' '} <a href="#signin" style={{color: '#3b82f6', textDecoration: 'none', fontWeight: '500'}}> ログイン </a> </span> ), }, }, }, blockOrder: defaultBlockOrder, })} </SignUp> ); }
🔧 Props Reference
Main Component Props
| Prop | Type | Default | Description |
|---|---|---|---|
onSubmit | SubmitHandler<T> | Required | Callback function triggered when form is submitted with valid data |
onChange | (setError, getValues, clearErrors) => void | Required | Callback function triggered when form values change. Provides form control functions for validation |
defaultData | DefaultValues<T> | undefined | Default form values to populate fields on initial render |
data | T | undefined | Controlled form values - use this for external form state management |
termsOfUseUrl | string | "/terms-of-use" | URL for the terms of use link |
privacyPolicyUrl | string | "/privacy-policy" | URL for the privacy policy link |
loginUrl | string | "/auth/login" | URL for the login link in GotoSignIn component |
className | string | undefined | Additional CSS class name for styling the form container |
sx | SxProps | undefined | MUI sx prop for custom styling |
children | BlocksOverride | undefined | Custom block components to override default rendering |
Note: This component extends MUI StackProps<'form'> (excluding children, onChange, and onSubmit). Uses component="form" with default spacing={4}, maxWidth: 496, px: 5, py: 6, and borderRadius: 3.
Sub-Components
The SignUp component provides several sub-components. All sub-components receive their default values from the main component's context and can override these values through props.
SignUp.SignUpTitle
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | "Create Your Account" | Title content |
className | string | undefined | Additional CSS class name for styling |
variant | string | "h4" | MUI Typography variant |
component | string | "h1" | HTML element to render |
sx | SxProps | undefined | MUI sx prop with default textAlign: 'center' |
Note: This component extends MUI TypographyProps.
SignUp.EmailField
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | "email" | Field name used for form data and validation |
label | string | "Email Address" | Field label displayed above the input |
placeholder | string | "Enter your email address" | Placeholder text shown when field is empty |
autoComplete | string | "username" | Browser autocomplete hint |
required | boolean | true | Whether the field is required |
fullWidth | boolean | true | Whether field takes full width |
className | string | undefined | Additional CSS class name for styling |
Note: This component extends MUI TextFieldProps. Error states and helper text are managed automatically by react-hook-form.
SignUp.PasswordField
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | "password" | Field name used for form data and validation |
label | string | "Password" | Field label displayed above the input |
placeholder | string | "Enter your password" | Placeholder text shown when field is empty |
autoComplete | string | "new-password" | Browser autocomplete hint |
required | boolean | true | Whether the field is required |
fullWidth | boolean | true | Whether field takes full width |
className | string | undefined | Additional CSS class name for styling |
Note: This component extends MUI TextFieldProps (excluding type). Includes built-in password visibility toggle with Visibility/VisibilityOff icons.
SignUp.TermsOfUse
| Prop | Type | Default | Description |
|---|---|---|---|
termsOfUseUrl | string | From context | URL for the terms of use link |
name | string | "agreesUserAgreement" | Field name used for form data and validation |
label | ReactNode | Link to terms of use | Content for the checkbox label |
required | boolean | undefined | Whether the checkbox is required |
className | string | undefined | Additional CSS class name for styling |
sx | SxProps | undefined | MUI sx prop for custom styling |
Note: This component extends MUI FormControlLabelProps (excluding control). Default link points to /terms-of-use and opens in new tab.
SignUp.PrivacyPolicy
| Prop | Type | Default | Description |
|---|---|---|---|
privacyPolicyUrl | string | From context | URL for the privacy policy link |
name | string | "agreesPrivacyPolicy" | Field name used for form data and validation |
label | ReactNode | Link to privacy policy | Content for the checkbox label |
required | boolean | undefined | Whether the checkbox is required |
className | string | undefined | Additional CSS class name for styling |
sx | SxProps | undefined | MUI sx prop for custom styling |
Note: This component extends MUI FormControlLabelProps (excluding control). Default link points to /privacy-policy and opens in new tab.
SignUp.SignUpButton
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | "Sign Up" | Button text content |
variant | string | "contained" | MUI Button variant |
size | string | "large" | MUI Button size |
type | string | "submit" | HTML button type |
fullWidth | boolean | true | Whether button takes full width |
className | string | undefined | Additional CSS class name for styling |
Note: This component extends MUI ButtonProps.
SignUp.GotoSignIn
| Prop | Type | Default | Description |
|---|---|---|---|
loginUrl | string | From context | URL for the sign in link |
children | ReactNode | Link to /auth/login | Content for the sign in link section |
className | string | undefined | Additional CSS class name for styling |
sx | SxProps | undefined | MUI sx prop with default textAlign: 'center' |
Note: This component extends MUI BoxProps.
🎨 Configuration examples
Custom Validation
function ValidationSignUp() {
const handleSubmit = (formData: SignUpFormData): void => {
console.log('Validated form submitted:', formData);
};
return (
<SignUp
onChange={(setError, getValues, clearErrors) => {
const {email, password} = getValues();
if (email && !email.includes('@')) {
setError('email', {message: 'Please enter a valid email'});
} else {
clearErrors('email');
}
if (password && password.length < 8) {
setError('password', {message: 'Password must be at least 8 characters'});
} else {
clearErrors('password');
}
}}
onSubmit={handleSubmit}
>
<SignUp.SignUpTitle
variant="h3"
sx={{
color: 'primary.main',
fontWeight: 'bold',
}}
>
Join Our Platform
</SignUp.SignUpTitle>
<SignUp.EmailField label="Corporate Email" placeholder="name@company.com" />
<SignUp.PasswordField label="Create Password" placeholder="Minimum 8 characters" />
<SignUp.TermsOfUse name="agreesUserAgreement" />
<SignUp.PrivacyPolicy name="agreesPrivacyPolicy" />
<SignUp.SignUpButton>Sign Up</SignUp.SignUpButton>
<SignUp.GotoSignIn />
</SignUp>
);
}
Custom Terms and Privacy Links
function CustomTermsSignUp() {
return (
<SignUp
termsOfUseUrl="https://example.com#terms"
privacyPolicyUrl="https://example.com#privacy"
loginUrl="/login"
onSubmit={data => console.log(data)}
onChange={() => {}}
>
<SignUp.SignUpTitle>Create Account</SignUp.SignUpTitle>
<SignUp.EmailField />
<SignUp.PasswordField />
<SignUp.TermsOfUse
label={
<span>
I accept the <a href="#terms">Terms of Service</a> and <a href="#conditions">Conditions</a>
</span>
}
/>
<SignUp.PrivacyPolicy
label={
<span>
I have read the <a href="#privacy">Privacy Policy</a>
</span>
}
/>
<SignUp.SignUpButton>Create Account</SignUp.SignUpButton>
<SignUp.GotoSignIn />
</SignUp>
);
}
Block Override Pattern
function BlockOverrideSignUp() {
return (
<SignUp onSubmit={data => console.log(data)} onChange={() => {}}>
{({defaultBlocks}) => ({
blocks: {
...defaultBlocks,
// Add custom welcome message
welcomeMessage: (
<div
style={{
padding: '12px 16px',
backgroundColor: '#e3f2fd',
borderRadius: '8px',
textAlign: 'center',
color: '#1976d2',
}}
>
Create your free account today!
</div>
),
},
blockOrder: [
'signUpTitle',
'welcomeMessage',
'emailField',
'passwordField',
'termsOfUse',
'privacyPolicy',
'signUpButton',
'gotoSignIn',
],
})}
</SignUp>
);
}
🔧 TypeScript Support
Full TypeScript support with comprehensive type definitions:
import {SignUp} from '@nodeblocks/frontend-signup-block';
import {
UseFormClearErrors,
UseFormGetValues,
UseFormSetError,
SubmitHandler,
} from 'react-hook-form';
// Default form data structure
type DefaultSignUpFormData = {
email?: string;
password?: string;
agreesPrivacyPolicy?: boolean;
agreesUserAgreement?: boolean;
};
// Extended form data type
type SignUpFormData = DefaultSignUpFormData & Record<string, unknown>;
// Custom form data with additional fields
interface CustomSignUpFormData extends SignUpFormData {
firstName?: string;
lastName?: string;
phone?: string;
}
function TypedSignUpExample() {
const handleSubmit: SubmitHandler<CustomSignUpFormData> = formData => {
console.log('Form submitted:', formData);
};
const handleChange = (
setError: UseFormSetError<CustomSignUpFormData>,
getValues: UseFormGetValues<CustomSignUpFormData>,
clearErrors: UseFormClearErrors<CustomSignUpFormData>,
): void => {
const values = getValues();
// Custom validation
if (values.email && !values.email.includes('@')) {
setError('email', {message: 'Invalid email format'});
} else {
clearErrors('email');
}
};
return (
<SignUp<CustomSignUpFormData>
onSubmit={handleSubmit}
onChange={handleChange}
defaultData={{email: ''}}
termsOfUseUrl="#terms"
privacyPolicyUrl="#privacy"
loginUrl="/signin"
sx={{maxWidth: 480, mx: 'auto'}}
>
<SignUp.SignUpTitle>Create Account</SignUp.SignUpTitle>
<SignUp.TextField name="firstName" label="First Name" placeholder="Enter your first name" />
<SignUp.TextField name="lastName" label="Last Name" placeholder="Enter your last name" />
<SignUp.EmailField />
<SignUp.PasswordField />
<SignUp.TermsOfUse
label={
<span>
I agree to the <a href="#terms">Terms of Service</a>
</span>
}
/>
<SignUp.PrivacyPolicy
label={
<span>
I agree to the <a href="#privacy">Privacy Policy</a>
</span>
}
/>
<SignUp.SignUpButton>Register</SignUp.SignUpButton>
<SignUp.GotoSignIn>
<span>
Already have an account? <a href="#signin">Sign In</a>
</span>
</SignUp.GotoSignIn>
</SignUp>
);
}
📝 Notes
- The component uses MUI's
Stackcomponent as its base withcomponent="form" - Default spacing is
4withmaxWidth: 496,px: 5,py: 6, andborderRadius: 3 - Form state is managed by
react-hook-formwithmode: 'onBlur'for validation - The
onChangecallback is triggered when form values change (usinguseWatch) - Password field has built-in visibility toggle with MUI's
Visibility/VisibilityOfficons - Error states and helper text are automatically displayed based on validation
- Default blocks are:
signUpTitle,emailField,passwordField,termsOfUse,privacyPolicy,signUpButton,gotoSignIn - Additional utility fields available:
TextField,TimeField,CheckboxField,SelectField - CSS classes follow BEM-style naming:
nbb-signup,nbb-signup-title,nbb-signup-email-field, etc. - Terms of use link defaults to
/terms-of-useand opens in new tab - Privacy policy link defaults to
/privacy-policyand opens in new tab - Sign in link defaults to
/auth/login
Built with ❤️ using React, TypeScript, and MUI.