サインアップブロック
SignUp は MUI 上に構築された制御された登録フォームブロックです。
インストール
- npm
- yarn
- pnpm
- bun
npm install @nodeblocks/frontend-signup-block
yarn add @nodeblocks/frontend-signup-block
pnpm add @nodeblocks/frontend-signup-block
bun add @nodeblocks/frontend-signup-block
必要なもの
| 項目 | 重要な理由 |
|---|---|
data | フォーム state の単一の信頼できる情報源 |
onDataChange | 検証や分析のために更新済み state とメタデータを受け取ります |
errors (optional) | フィールド単位のエラーフィードバックを表示します |
termsOfUseUrl (optional) | 利用規約チェックボックスリンクの遷移先 URL(デフォルトは /terms-of-use) |
privacyPolicyUrl (optional) | プライバシーチェックボックスリンクの遷移先 URL(デフォルトは /privacy-policy) |
loginUrl (optional) | サインインリンクの遷移先 URL(デフォルトは /auth/login) |
SignUp はフォーム state を所有しません。state はアプリ側で保持し、data を通じて渡してください。デフォルトの形には email、password、agreesUserAgreement、agreesPrivacyPolicy が含まれます。
コード例
- クイックスタート
- ラベルと URL
- フォームエラー
- 複合コンポーネント
- ブロックの上書き
function Example() { const defaultData = { email: '', password: '', agreesUserAgreement: false, agreesPrivacyPolicy: false, }; const [data, setData] = React.useState(defaultData); return ( <SignUp data={data} onDataChange={(nextData) => { setData(nextData); }} /> ); }
function Example() { const defaultData = { email: '', password: '', agreesUserAgreement: false, agreesPrivacyPolicy: false, }; const [data, setData] = React.useState(defaultData); const labels = { signUpTitle: 'Create account', emailField: 'Work email', passwordField: 'Password', termsOfUse: 'I agree to the Terms of Use', privacyPolicy: 'I agree to the Privacy Policy', signUpButton: 'Register', gotoSignIn: 'Sign in', backButton: 'Back to previous page', }; const placeholders = { emailField: 'name@company.com', passwordField: 'At least 8 characters', }; return ( <SignUp data={data} onDataChange={(nextData) => { setData(nextData); }} labels={labels} placeholders={placeholders} termsOfUseUrl="/terms-of-use" privacyPolicyUrl="/privacy-policy" loginUrl="/auth/login" /> ); }
コピーの上書きにはルートで labels と placeholders を渡すか、個別のサブコンポーネントで設定してください(複合コンポーネント タブを参照)。チェックボックスのラベル(termsOfUse、privacyPolicy)は termsOfUseUrl と privacyPolicyUrl を使ってリンクとして表示されます。デフォルトのサインインリンクには loginUrl を使い、SignUp.GotoSignIn の children で上書きすることもできます。
function Example() { const defaultData = { email: '', password: '', agreesUserAgreement: false, agreesPrivacyPolicy: false, }; const [data, setData] = React.useState(defaultData); const [errors, setErrors] = React.useState({}); const handleDataChange = (nextData, meta) => { const { [meta.name]: _removed, ...restErrors } = errors; let nextErrors = restErrors; // Validate required fields on blur (same pattern as storybook) if (meta.cause === 'blur') { nextErrors = { ...restErrors }; if (meta.name === 'email' && !nextData.email) nextErrors.email = 'Email is required.'; if (meta.name === 'password' && !nextData.password) nextErrors.password = 'Password is required.'; } setErrors(nextErrors); setData(nextData); }; return ( <SignUp data={data} errors={Object.keys(errors).length ? errors : undefined} onDataChange={handleDataChange} /> ); }
まずアクティブなフィールドのエラーをクリアし、その後 blur 時に必須フィールドを再検証してください。
子ブロックを使って、制御された state の動作を保ちながらレイアウトをカスタマイズします。
function Example() { const defaultData = { email: '', password: '', agreesUserAgreement: false, agreesPrivacyPolicy: false, }; const [data, setData] = React.useState(defaultData); const [errors, setErrors] = React.useState({}); const handleDataChange = (nextData, meta) => { const {[meta.name]: _removed, ...restErrors} = errors; let nextErrors = restErrors; // Validate required fields on blur (same pattern as storybook) if (meta.cause === 'blur') { nextErrors = {...restErrors}; if (meta.name === 'email' && !nextData.email) nextErrors.email = 'Email is required.'; if (meta.name === 'password' && !nextData.password) nextErrors.password = 'Password is required.'; } setErrors(nextErrors); setData(nextData); }; return ( <SignUp data={data} errors={Object.keys(errors).length ? errors : undefined} onDataChange={handleDataChange} termsOfUseUrl="/terms-of-use" privacyPolicyUrl="/privacy-policy" loginUrl="/auth/login" > <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 termsOfUseUrl="/terms-of-use" /> <SignUp.PrivacyPolicy privacyPolicyUrl="/privacy-policy" /> <SignUp.SignUpButton>Sign Up</SignUp.SignUpButton> <SignUp.GotoSignIn loginUrl="/auth/login"> <span> Already have an account? <a href="#auth/login">Sign In</a> </span> </SignUp.GotoSignIn> </SignUp> ); }
関数 children を使ってデフォルトのブロックと順序を上書きします。
function Example() { const defaultData = { email: '', password: '', agreesUserAgreement: false, agreesPrivacyPolicy: false, }; const [data, setData] = React.useState(defaultData); const [errors, setErrors] = React.useState({}); const handleDataChange = (nextData, meta) => { const {[meta.name]: _removed, ...restErrors} = errors; let nextErrors = restErrors; // Validate required fields on blur (same pattern as storybook) if (meta.cause === 'blur') { nextErrors = {...restErrors}; if (meta.name === 'email' && !nextData.email) nextErrors.email = 'Email is required.'; if (meta.name === 'password' && !nextData.password) nextErrors.password = 'Password is required.'; } setErrors(nextErrors); setData(nextData); }; return ( <SignUp data={data} errors={Object.keys(errors).length ? errors : undefined} onDataChange={handleDataChange}> {({defaultBlocks, defaultBlockOrder}) => ({ blocks: { ...defaultBlocks, customNotification: ( <div style={{ background: '#eef4ff', border: '1px solid #cddcff', borderRadius: '8px', padding: '12px', fontSize: '14px', }} > Welcome! Fill in the form to create your account. </div> ), }, blockOrder: ['customNotification', ...defaultBlockOrder], })} </SignUp> ); }
ブロックの上書きを使うタイミング
順序を変えたいとき、デフォルトの UI ブロックを置き換えたいとき、共有 state の処理を維持しながらカスタムコンテンツを挿入したいときに上書きを使います。デフォルトの順序は signUpTitle、emailField、passwordField、termsOfUse、privacyPolicy、signUpButton、gotoSignIn、backButton です。不要な場合は blockOrder から backButton を外してください。特定のブロックの前にレスポンシブな余白を追加するには blockSpacingBefore を使ってください(ブロック上書きパターンのみ)。
重要な props
コア props
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
data | SignUpFormData ({ email, password, agreesUserAgreement, agreesPrivacyPolicy } or extended Record<string, unknown>) | Yes | - | 現在のフォーム data オブジェクト |
onDataChange | (data, meta) => void | Yes | - | 更新時に呼び出されます。meta には name、value、cause(input、change、blur、clear、reset、programmatic)、任意の event が含まれます |
errors | { [fieldName: string]: string | string[] } | No | undefined | data のフィールド名に紐づくフィールドエラー(例: email、password、agreesUserAgreement、agreesPrivacyPolicy) |
コンテンツ props
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
labels | { signUpTitle?, emailField?, passwordField?, termsOfUse?, privacyPolicy?, signUpButton?, gotoSignIn?, backButton? } | No | signUpTitle: 'Create Your Account', emailField: 'Email Address', passwordField: 'Password', termsOfUse: 'Accept the terms of use.', privacyPolicy: 'Accept the privacy policy.', signUpButton: 'Sign Up', gotoSignIn: 'Already have an account? Sign In.', backButton: 'Back to previous page' | デフォルトのテキストラベルを上書きします |
placeholders | { emailField?, passwordField? } | No | emailField: 'Enter your email address', passwordField: 'Enter your password' | メール / パスワードのプレースホルダーを上書きします |
termsOfUseUrl | string | No | /terms-of-use | 利用規約リンクの遷移先 URL |
privacyPolicyUrl | string | No | /privacy-policy | プライバシーリンクの遷移先 URL |
loginUrl | string | No | /auth/login | 「サインインへ移動」リンクの遷移先 URL |
レイアウトと構成 props
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
children | BlocksOverride | ReactNode | No | undefined | デフォルトのブロックを上書きするか、カスタムの JSX children を提供します |
blockSpacingBefore | Partial<Record<string, number | Partial<Record<'xs' | 'sm' | 'md' | 'lg' | 'xl', number>>>> | No | { passwordField: 3, termsOfUse: 3, privacyPolicy: 0 } | 列挙されたブロックの前に置くテーマ間隔。デフォルトブロックまたはブロック上書きパターンにのみ適用されます |
component | React.ElementType | No | 'form' | ルート要素の型 |
className | string | No | undefined | ルートコンテナのクラス名 |
sx | SxProps | No | undefined | ルートコンテナ向けの MUI システムスタイル |
SignUp は StackProps<'form'>(children を除く)も継承するため、onSubmit、id、noValidate などの標準的な form / stack props がサポートされます。上書きなしのデフォルトのブロック順は signUpTitle、emailField、passwordField、termsOfUse、privacyPolicy、signUpButton、gotoSignIn、backButton (defaultBlockOrder) です。
デフォルト UI ブロック
| ブロック | 基盤 | 補足 |
|---|---|---|
SignUp (root) | Stack (component="form") | 制御されたフォームコンテナ。最大幅 496px、中央寄せのカードレイアウト |
SignUp.SignUpTitle | Typography | タイトルテキストブロック(variant="h4")。labels.signUpTitle または children で上書き可能 |
SignUp.EmailField | TextField | メール入力(name="email", autoComplete="username")。デフォルトラベルは Email Address、プレースホルダーは Enter your email address |
SignUp.PasswordField | TextField + IconButton | 表示切り替え付きのパスワード入力。autoComplete="new-password"。デフォルトラベルは Password、プレースホルダーは Enter your password |
SignUp.TermsOfUse | Checkbox + FormControlLabel + Link | チェックボックス(name="agreesUserAgreement")。ラベルは termsOfUseUrl へのリンク(target="_blank")です |
SignUp.PrivacyPolicy | Checkbox + FormControlLabel + Link | チェックボックス(name="agreesPrivacyPolicy")。ラベルは privacyPolicyUrl へのリンク(target="_blank")です |
SignUp.SignUpButton | Button | 送信ボタン(variant="contained"、size="large"、type="submit"、fullWidth) |
SignUp.GotoSignIn | Box + Link | サインインへのナビゲーション。loginUrl またはカスタム children を使用 |
SignUp.BackButton | Button | 補助アクション(variant="outlined"、size="large"、type="button"、fullWidth)。デフォルト順に含まれます。不要なら blockOrder から外してください |
追加のフィールドプリミティブ
| プリミティブ | 基盤 | 補足 |
|---|---|---|
SignUp.TextField | TextField | 汎用テキスト入力 |
SignUp.TimeField | TextField | 時刻入力(type="time") |
SignUp.CheckboxField | Checkbox + FormControl | ヘルパーテキスト / エラーテキスト付きのチェックボックス |
SignUp.SelectField | Select + TextField | MUI TextField 経由で表示されるセレクト入力 |
TypeScript
import {SignUp, SignUpFormData} from '@nodeblocks/frontend-signup-block';
type MySignUpData = SignUpFormData & {
companyName?: string;
};