1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【React】Atomic Designを使って登録フォームを作成する

Last updated at Posted at 2025-12-30

React + TypeScript (.tsx) で、AtomicDesign(アトミックデザイン)に基づいた「管理者登録画面」を設計・実装していきます。

この記事では、Atomic Designに特化した記事であるためtailwindCSSは今は導入していません。

Atomic Designを設計するためのポイント

ReactNext.jsはコンポーネント単位を組み合わせてアプリを作り上げるフレームワークなので、下記の概念をしっかり意識することが上達の近道です。

コンポーネント 用途
Atoms 再利用可能・意味を持たない
Molecules フォームの「部品」
Organisms 業務ロジックを持つ(state / API)
Templates レイアウトのみ
Pages ルーティングと画面単位
👉 管理者編集画面・一覧画面を作るときも
Atoms / Molecules をそのまま使い回せるのが強みです。

完成イメージ

image.png

ページルーティングのライブラリを導入

まず最初に、Reactでは、ページルーティングのためのライブラリを導入していきます。

react-router-dom

アトミックデザインの構成

src/
├─ components/
│  ├─ atoms/
│  │  ├─ Button.tsx
│  │  ├─ Input.tsx
│  │  ├─ Checkbox.tsx
│  │  └─ Label.tsx
│  ├─ molecules/
│  │  ├─ FormField.tsx
│  │  └─ PasswordField.tsx
│  ├─ organisms/
│  │  └─ AdminUserForm.tsx
│  └─ templates/
│     └─ AdminUserTemplate.tsx
├─ pages/
│  └─ AdminUserRegisterPage.tsx

つぎは、いよいよ各コンポーネントを作成していきます。

srcフォルダ配下に新規フォルダcomponentsを作成します。
componentsフォルダの中には、atomesフォルダ、moleculesフォルダ、organismsフォルダ、templatesフォルダをそれぞれ作成しておきます。

Atoms(最小単位)の作成

Input.tsx
type Props = {
    value: string;
    onChange: (e:React.ChangeEvent<HTMLInputElement>)=>void;
    type?: string;
    name?: string;
}

export const Input:React.FC<Props>=({
    value,
    onChange,
    type = "text",
    name,
})=>(
    <input
        type={type}
        name={name}
        value={value}
        onChange={onChange}
        style={{ padding: "8px", width: "100%" }}
    />
);
Label.tsx
type Props = {
    text:string;
}

export const Label:React.FC<Props> = ({ text })=>(
    <label style={{ display: "block", marginBottom: "4px" }}>
        { text }
    </label>
);
Button.tsx
type Props = {
  text: string;
  onClick?: () => void;
  type?: "button" | "submit";
};

export const Button: React.FC<Props> = ({
  text,
  onClick,
  type = "button",
}) => (
  <button 
    type={type} 
    onClick={onClick} 
    style={{ padding: "8px 16px" }}>
    {text}
  </button>
);

Checkbox.tsx
type Props = {
    checked: boolean;
    onChange:(e:React.ChangeEvent<HTMLInputElement>)=>void;
}

export const Checkbox:React.FC<Props> = ({ checked, onChange })=>(
    <input type="checkbox" checked={checked} onChange={onChange}/>
)

Molecules(意味を持つ部品)の作成

FormField.tsx(Label + Input)を作成します。

FormField.tsx
import { Input } from "../atoms/Input";
import { Label } from "../atoms/Label";

type Props = {
  label: string;
  value: string;
  onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
  type?: string;
};

export const FormField: React.FC<Props> = ({
    label,
    value,
    onChange,
    type,
})=>(
    <div style={{ marginBottom: "12px" }}>
        <Label text={label}/>
        <Input value={value} onChange={onChange} type={type}/>
    </div>
)
PasswordField.tsx
import { FormField } from "./FormField";

type Props = {
    value: string;
    onChange:(e:React.ChangeEvent<HTMLInputElement>)=>void;
};

export const PasswordField:React.FC<Props> = ({
    value,
    onChange,
})=>(
    <FormField
        label="パスワード"
        value={value}
        onChange={onChange}
        type="password"
    />
)

Organisms(フォーム全体)

AdminUserForm.tsx
import { useState } from "react";
import { PasswordField } from "../molecules/PasswordField";
import { FormField } from "../molecules/FormField";
import { Checkbox } from "../atoms/Checkbox";
import { Button } from "../atoms/Button";

export const AdminUserForm:React.FC = ()=>{
    const [id,setId] = useState("");
    const [name, setName] = useState("");
    const [email, setEmail] = useState("");
    const [password, setPassword] = useState("");
    const [adminrole, setAdminrole] = useState(false);

    const handleSubmit = async(e:React.FormEvent)=>{
        e.preventDefault();
        const body = {
            id,
            name,
            email,
            password,
            adminrole
        };

        await fetch("/api/adminusers",{
            method:"POST",
            headers:{ "Content-Type": "application/json" },
            body:JSON.stringify(body),
        });

        alert("管理者を登録しました");
    };
    return (
        <form onSubmit={handleSubmit}>
            <FormField label="社員番号" value={id} onChange={(e)=>setId(e.target.value)}/>
            <FormField label="氏名" value={name} onChange={(e)=>setName(e.target.value)}/>
            <FormField label="メールアドレス" value={email} onChange={(e)=>setEmail(e.target.value)}/>
            <PasswordField value={password} onChange={(e) => setPassword(e.target.value)} />
            <div style={{ marginBottom: "12px" }}>
                <label>
                    <Checkbox checked={adminrole} onChange={(e)=>setAdminrole(e.target.checked)}/>
                    管理者権限
                </label>
                <Button type="submit" text="登録"/>
            </div>
        </form>
    )
}


Template(レイアウト)の作成

AdminUserTemplate.tsx
import { AdminUserForm } from "../organisms/AdminUserForm";

export const AdminUserTemplate: React.FC = () => (
  <div style={{ maxWidth: "400px", margin: "0 auto" }}>
    <h1>管理者登録</h1>
    <AdminUserForm />
  </div>
);

Page(ルーティング単位)の作成

srcフォルダ配下に新規フォルダpagesを作成します。

AdminUserRegisterPage.tsx
import { AdminUserTemplate } from "../components/templates/AdminUserTemplate";

export const AdminUserRegisterPage:React.FC = ()=>{
    return <AdminUserTemplate />
}

React では URL(パス)と Page コンポーネントをルーティングで結び付けることで
AdminUserRegisterPage
を表示します。

ここでは React Router v6 を使う前提で説明します(現在の主流です)。

ルーティング設定(App.tsx)

App.tsx
import './App.css'
import { BrowserRouter, Routes, Route } from 'react-router-dom'// react-router-domを追加
import { AdminUserRegisterPage } from './pages/AdminUserRegisterPage'

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route
          path="/admin/users/new"
          element={<AdminUserRegisterPage />}
        />
      </Routes>
    </BrowserRouter>
  )
}

export default App

実際にアクセスするURL

ローカル開発環境(例:Vite / CRA)の場合:

http://localhost:3000/admin/users/new

※ Vite ならポートは 5173 になることもあります。

http://localhost:5173/admin/users/new

URL設計の考え方(REST寄り)

目的 URL
管理者登録 /admin/users/new
管理者一覧 /admin/users
管理者詳細 /admin/users/:id
管理者編集 /admin/users/:id/edit

おまけ メニューやボタンから遷移する場合

sample.tsx
import { Link } from "react-router-dom";

<Link to="/admin/users/new">管理者登録</Link>

以上です。

サイト

Atomic Designの概念

【Atomic Design】Xの画面を見ながらAtomic Designを学ぶ

アトミックデザインをReactで導入してみた

React で実装する atomic design のコンポーネントごとの責務の分け方とコード規約

1
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?