サインインブロック
SignIn は MUI 上に構築された制御されたサインインフォームブロックです。
インストール
- npm
- yarn
- pnpm
- bun
npm install @nodeblocks/frontend-signin-block
yarn add @nodeblocks/frontend-signin-block
pnpm add @nodeblocks/frontend-signin-block
bun add @nodeblocks/frontend-signin-block
必要なもの
| 項目 | 重要な理由 |
|---|---|
data | フォーム state の単一の信頼できる情報源 |
onDataChange | 検証や分析のために更新済み state とメタデータを受け取ります |
errors (optional) | フィールド単位のエラーフィードバックを表示します |
signupUrl (optional) | サインアップリンクの遷移先 URL(デフォルトは /auth/signup) |
resetPasswordUrl (optional) | パスワードを忘れた場合のリンクの遷移先 URL(デフォルトは /auth/resetpassword) |
SignIn はフォーム state を所有しません。state はアプリ側で保持し、data を通じて渡してください。
コード例
- クイックスタート
- ラベルと URL
- フォームエラー
- 複合コンポーネント
- ブロックの上書き
function Example() { const defaultData = { email: '', password: '', }; const [data, setData] = React.useState(defaultData); return ( <SignIn data={data} onDataChange={(nextData) => { setData(nextData); }} /> ); }
function Example() { const defaultData = { email: '', password: '', }; const [data, setData] = React.useState(defaultData); const labels = { signInTitle: 'Welcome back', emailField: 'Work email', passwordField: 'Password', signInButton: 'Sign in', gotoSignUp: 'Create an account', resetPassword: 'Forgot your password?', }; const placeholders = { emailField: 'name@company.com', passwordField: 'Enter your password', }; return ( <SignIn data={data} onDataChange={(nextData) => { setData(nextData); }} labels={labels} placeholders={placeholders} signupUrl="/auth/signup" resetPasswordUrl="/auth/resetpassword" /> ); }
コピーの上書きにはルートで labels と placeholders を渡すか、個別のサブコンポーネントで設定してください(複合コンポーネント タブを参照)。signupUrl と resetPasswordUrl は遷移先に使い、リンク内容は SignIn.GotoSignUp または SignIn.ResetPassword の children で上書きできます。
function Example() { const defaultData = { email: '', password: '', }; 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 ( <SignIn data={data} errors={Object.keys(errors).length ? errors : undefined} onDataChange={handleDataChange} /> ); }
まずアクティブなフィールドのエラーをクリアし、その後 blur 時に必須フィールドを再検証してください。
子ブロックを使って、制御された state の動作を保ちながらレイアウトをカスタマイズします。
function Example() { const defaultData = { email: '', password: '', }; 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 ( <SignIn data={data} errors={Object.keys(errors).length ? errors : undefined} onDataChange={handleDataChange} signupUrl="/auth/signup" resetPasswordUrl="/auth/resetpassword" > <SignIn.SignInTitle>Welcome Back</SignIn.SignInTitle> <SignIn.EmailField label="Email Address" placeholder="Enter your email" /> <SignIn.PasswordField label="Password" placeholder="Enter your password" /> <SignIn.SignInButton>Sign In</SignIn.SignInButton> <SignIn.GotoSignUp> <a href="#auth/signup">Create an account</a> </SignIn.GotoSignUp> <SignIn.ResetPassword> <a href="#auth/resetpassword">Forgot password?</a> </SignIn.ResetPassword> </SignIn> ); }
関数 children を使ってデフォルトのブロックと順序を上書きします。
function Example() { const defaultData = { email: '', password: '', }; 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 ( <SignIn 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 back! Please sign in to continue. </div> ), }, blockOrder: ['customNotification', ...defaultBlockOrder], })} </SignIn> ); }
ブロックの上書きを使うタイミング
順序を変えたいとき、デフォルトの UI ブロックを置き換えたいとき、共有 state の処理を維持しながらカスタムコンテンツを挿入したいときに上書きを使います。デフォルトの順序は signInTitle, emailField, passwordField, signInButton, resetPassword, gotoSignUp です。特定のブロックの前にレスポンシブな余白を追加するには blockSpacingBefore を使ってください(ブロック上書きパターンのみ)。
重要な props
コア props
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
data | SignInFormData ({ email, password } or extended Record<string, unknown>) | Yes | - | 現在のフォーム data オブジェクト |
onDataChange | (data, meta) => void | Yes | - | 更新時に呼び出されます。meta には name, value, cause (input, change, blur, clear, reset, programmatic), optional event が含まれます |
errors | { [fieldName: string]: string | string[] } | No | undefined | data のフィールドパスに紐づくフィールドエラー(例: email, password、または data を拡張した場合のネストされたパス) |
コンテンツ props
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
labels | { signInTitle?, emailField?, passwordField?, signInButton?, gotoSignUp?, resetPassword? } | No | signInTitle: 'Sign In', emailField: 'Email', passwordField: 'Password', signInButton: 'Sign In', gotoSignUp: 'Create an account', resetPassword: 'Forgot your password?' | デフォルトのテキストラベルを上書きします |
placeholders | { emailField?, passwordField? } | No | emailField: 'Please enter your email', passwordField: 'Please enter your password' | メール / パスワードのプレースホルダーを上書きします |
signupUrl | string | No | /auth/signup | サインアップリンクの遷移先 URL |
resetPasswordUrl | string | No | /auth/resetpassword | パスワードリセットリンクの遷移先 URL |
レイアウトと構成 props
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
children | BlocksOverride | ReactNode | No | undefined | デフォルトのブロックを上書きするか、カスタムの JSX children を提供します |
blockSpacingBefore | Partial<Record<string, number | Partial<Record<'xs' | 'sm' | 'md' | 'lg' | 'xl', number>>>> | No | { passwordField: { xs: 3, sm: 4 } } | 列挙されたブロックの前に置くテーマ間隔。デフォルトブロックまたはブロック上書きパターンにのみ適用されます |
component | React.ElementType | No | 'form' | ルート要素の型 |
className | string | No | undefined | ルートコンテナのクラス名 |
sx | SxProps | No | undefined | ルートコンテナ向けの MUI システムスタイル |
SignIn は StackProps<'form'>(children を除く)も継承するため、onSubmit、id、noValidate などの標準的な form / stack props がサポートされます。上書きなしのデフォルトのブロック順は signInTitle, emailField, passwordField, signInButton, resetPassword, gotoSignUp (defaultBlockOrder) です。
デフォルト UI ブロック
| ブロック | 基盤 | 補足 |
|---|---|---|
SignIn (root) | Stack (component="form") | 制御されたフォームコンテナ。最大幅 496px、中央寄せのカードレイアウト |
SignIn.SignInTitle | Typography | タイトルテキストブロック(variant="h4")。labels.signInTitle または children で上書き可能 |
SignIn.EmailField | TextField | メール入力(name="email", autoComplete="username") |
SignIn.PasswordField | TextField + IconButton | 表示切り替え付きのパスワード入力。autoComplete="current-password" |
SignIn.SignInButton | Button | 送信ボタン(variant="contained", size="large", type="submit", fullWidth) |
SignIn.ResetPassword | Box + Link | パスワードを忘れた場合のリンク。resetPasswordUrl またはカスタム children を使用 |
SignIn.GotoSignUp | Box + Link | サインアップへのナビゲーションリンク。signupUrl またはカスタム children を使用 |
追加のフィールドプリミティブ
| プリミティブ | 基盤 | 補足 |
|---|---|---|
SignIn.TextField | TextField | 汎用テキスト入力 |
SignIn.TimeField | TextField | 時刻入力(type="time") |
SignIn.CheckboxField | Checkbox + FormControl | ヘルパーテキスト / エラーテキスト付きのチェックボックス |
SignIn.SelectField | Select + TextField | MUI TextField 経由で表示されるセレクト入力 |
TypeScript
import {SignIn, SignInFormData} from '@nodeblocks/frontend-signin-block';
type MySignInData = SignInFormData & {
rememberMe?: boolean;
};