[React+Tailwind] Flowbite で Form を表示してみる | 心を無にして始める React
準備
Flowbite が使えるプロジェクトを準備します。
Form コンポーネントをつくる
./src/components 配下に Form.js を作ります。
入力に使いそうなコントロールをまとめて実装します。
- ラベル (Label)
- テキストボックス (TextInput)
- テキストエリア (Textarea)
- チェックボックス (Checkbox)
- セレクトボックス (Select)
- ラジオボタン (Radio)
- トグルボタン (ToggleSwitch)
- ファイル選択 (File)
import { forwardRef } from 'react';
import {
Checkbox as FlowbiteCheckbox,
FileInput as FlowbiteFileInput,
Label as FlowbiteLabel,
Radio as FlowbiteRadio,
Select as FlowbiteSelect,
Textarea as FlowbiteTextarea,
TextInput as FlowbiteTextInput,
ToggleSwitch as FlowbiteToggleSwitch,
} from 'flowbite-react';
const Form = forwardRef((
{
children,
...otherProps
},
ref,
) => {
return (
<form
ref={ref}
{...otherProps}
>
{children}
</form>
);
});
const Checkbox = forwardRef((
{
...otherProps
},
ref,
) => {
return (
<FlowbiteCheckbox
ref={ref}
{...otherProps}
/>
);
});
const FileInput = forwardRef((
{
color = "gray",
helperText,
sizing = "md",
...otherProps
},
ref,
) => {
return (
<FlowbiteFileInput
color={color}
helperText={helperText}
ref={ref}
sizing={sizing}
{...otherProps}
/>
);
});
const Label = forwardRef((
{
children,
color = 'default',
disabled = false,
value,
...otherProps
},
ref,
) => {
return (
<FlowbiteLabel
color={color}
disabled={disabled}
ref={ref}
value={value}
{...otherProps}
>
{children}
</FlowbiteLabel>
);
});
const Radio = forwardRef((
{
...otherProps
},
ref,
) => {
return (
<FlowbiteRadio
ref={ref}
{...otherProps}
/>
);
});
const Select = forwardRef((
{
addon,
children,
color = 'gray',
helperText,
icon,
shadow = false,
sizing = 'md',
...otherProps
},
ref,
) => {
return (
<FlowbiteSelect
addon={addon}
color={color}
helperText={helperText}
icon={icon}
ref={ref}
shadow={shadow}
sizing={sizing}
{...otherProps}
>
{children}
</FlowbiteSelect>
);
});
const Textarea = forwardRef((
{
color = 'gray',
helperText,
shadow = false,
...otherProps
},
ref,
) => {
return (
<FlowbiteTextarea
color={color}
helperText={helperText}
ref={ref}
shadow={shadow}
{...otherProps}
/>
);
});
const TextInput = forwardRef((
{
addon,
color = 'gray',
helperText,
icon,
shadow = false,
sizing = 'md',
...otherProps
},
ref,
) => {
return (
<FlowbiteTextInput
addon={addon}
color={color}
helperText={helperText}
icon={icon}
ref={ref}
shadow={shadow}
sizing={sizing}
{...otherProps}
/>
);
});
const ToggleSwitch = forwardRef((
{
checked = false,
label,
onChange,
...otherProps
},
ref,
) => {
return (
<FlowbiteToggleSwitch
checked={checked}
label={label}
onChange={onChange}
ref={ref}
{...otherProps}
/>
);
});
export default Object.assign(Form, {
Checkbox,
FileInput,
Label,
Radio,
Select,
Textarea,
TextInput,
ToggleSwitch,
});
Form コンポーネントをつかう
いつものように App.js を編集していきます。
import { useState } from 'react';
import { EnvelopeIcon } from '@heroicons/react/24/solid';
import Form from './components/Form';
import './App.css';
function App() {
const [checked, setChecked] = useState(false);
return (
<div className="dark">
<div className="min-h-screen p-8 flex flex-col justify-center items-center dark:!bg-gray-900">
<div className="w-1/2">
<Form className="flex flex-col gap-3">
<div>
<div className="mb-2 block">
<Form.Label
htmlFor="email1"
value="Your email"
/>
</div>
<Form.TextInput
id="email1"
type="email"
placeholder="name@example.com"
required={true}
icon={EnvelopeIcon}
/>
</div>
<div>
<div className="mb-2 block">
<Form.Label
htmlFor="password1"
value="Your password"
/>
</div>
<Form.TextInput
id="password1"
type="password"
required={true}
/>
</div>
<div className="flex items-center gap-2">
<Form.Checkbox id="remember" />
<Form.Label htmlFor="remember">
Remember me
</Form.Label>
</div>
<hr />
<div>
<div className="mb-2 block">
<Form.Label
htmlFor="countries"
value="Select your country"
/>
</div>
<Form.Select
id="countries"
required={true}
>
<option>
United States
</option>
<option>
Canada
</option>
<option>
France
</option>
<option>
Germany
</option>
</Form.Select>
</div>
<fieldset
className="flex flex-col gap-4"
id="radio"
>
<legend className="mb-3 dark:text-white">
Choose your favorite country
</legend>
<div className="flex items-center gap-2">
<Form.Radio
id="united-state"
name="countries"
value="USA"
defaultChecked={true}
/>
<Form.Label htmlFor="united-state">
United States
</Form.Label>
</div>
<div className="flex items-center gap-2">
<Form.Radio
id="germany"
name="countries"
value="Germany"
/>
<Form.Label htmlFor="germany">
Germany
</Form.Label>
</div>
<div className="flex items-center gap-2">
<Form.Radio
id="spain"
name="countries"
value="Spain"
/>
<Form.Label htmlFor="spain">
Spain
</Form.Label>
</div>
<div className="flex items-center gap-2">
<Form.Radio
id="uk"
name="countries"
value="United Kingdom"
/>
<Form.Label htmlFor="uk">
United Kingdom
</Form.Label>
</div>
<div className="flex items-center gap-2">
<Form.Radio
id="china"
name="countries"
value="China"
disabled={true}
/>
<Form.Label
htmlFor="china"
disabled={true}
>
China (disabled)
</Form.Label>
</div>
</fieldset>
<div>
<div className="mb-2 block">
<Form.Label
htmlFor="file"
value="Upload file"
/>
</div>
<Form.FileInput
id="file"
helperText="A profile picture is useful to confirm your are logged into your account"
/>
</div>
<div
className="flex flex-col gap-4"
>
<Form.ToggleSwitch
checked={checked}
label="Toggle me"
onChange={() => { setChecked(!checked) }}
/>
</div>
<hr />
<div>
<div className="mb-2 block">
<Form.Label
htmlFor="small"
value="Small input"
/>
</div>
<Form.TextInput
id="small"
type="text"
sizing="sm"
shadow={true}
helperText={<span>This is helper text. Small input.</span>}
/>
</div>
<div>
<div className="mb-2 block">
<Form.Label
htmlFor="base"
value="Base input"
/>
</div>
<Form.TextInput
id="base"
type="text"
sizing="md"
shadow={true}
helperText={<span>This is helper text. Medium input.</span>}
/>
</div>
<div>
<div className="mb-2 block">
<Form.Label
htmlFor="large"
value="Large input"
/>
</div>
<Form.TextInput
id="large"
type="text"
sizing="lg"
shadow={true}
helperText={<span>This is helper text. Large input.</span>}
/>
</div>
<div>
<div className="mb-2 block">
<Form.Label
htmlFor="comment"
value="Your message"
/>
</div>
<Form.Textarea
id="comment"
placeholder="Leave a comment..."
required={true}
rows={4}
/>
</div>
<hr />
<div>
<div className="mb-2 block">
<Form.Label
htmlFor="username"
value="Username"
/>
</div>
<Form.TextInput
id="username3"
placeholder="Bonnie Green"
required={true}
addon="@"
/>
</div>
</Form>
</div>
<div className="mt-4 flex gap-3">
</div>
</div>
</div>
);
}
export default App;
結果
はい、できました。