Form フォーム
LhForm と LhFormItem がモデルバインディング、必須バリデーション、フィールドエラーの表示を提供します。
基本的な使い方
基本的な使い方
vue
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { LhForm, LhFormItem, LhInput, LhButton, LhMessage } from '@lh-ui/vue3'
const formRef = ref()
const formModel = reactive({
name: '',
email: '',
})
const formRules = {
name: [{ required: true, message: '氏名を入力してください' }],
email: [{ required: true, message: 'メールアドレスを入力してください' }],
}
async function submitForm() {
const valid = await formRef.value.validate()
if (valid) {
LhMessage.success('送信に成功しました')
console.log('送信に成功しました', formModel)
}
}
function resetForm() {
formRef.value?.resetFields()
}
</script>
<template>
<LhForm ref="formRef" :model="formModel" :rules="formRules" label-width="80px">
<LhFormItem prop="name" label="氏名" required>
<LhInput v-model="formModel.name" placeholder="氏名を入力してください" />
</LhFormItem>
<LhFormItem prop="email" label="メールアドレス" required>
<LhInput v-model="formModel.email" placeholder="メールアドレスを入力してください" />
</LhFormItem>
<LhFormItem>
<LhButton type="primary" @click="submitForm">送信</LhButton>
<LhButton plain @click="resetForm" style="margin-left: 8px">リセット</LhButton>
</LhFormItem>
</LhForm>
</template>vue
<script>
import { LhForm, LhFormItem, LhInput, LhButton, LhMessage } from '@lh-ui/vue3'
export default {
components: { LhForm, LhFormItem, LhInput, LhButton },
data() {
return {
formModel: { name: '', email: '' },
formRules: {
name: [{ required: true, message: '氏名を入力してください' }],
email: [{ required: true, message: 'メールアドレスを入力してください' }],
},
}
},
methods: {
async submitForm() {
const valid = await this.$refs.formRef.validate()
if (valid) {
LhMessage.success('送信に成功しました')
console.log('送信に成功しました', this.formModel)
}
},
resetForm() { this.$refs.formRef?.resetFields() },
},
}
</script>
<template>
<LhForm ref="formRef" :model="formModel" :rules="formRules" label-width="80px">
<LhFormItem prop="name" label="氏名" required>
<LhInput v-model="formModel.name" placeholder="氏名を入力してください" />
</LhFormItem>
<LhFormItem prop="email" label="メールアドレス" required>
<LhInput v-model="formModel.email" placeholder="メールアドレスを入力してください" />
</LhFormItem>
<LhFormItem>
<LhButton type="primary" @click="submitForm">送信</LhButton>
<LhButton plain @click="resetForm">リセット</LhButton>
</LhFormItem>
</LhForm>
</template>カスタムテーマ
フォームにカスタムテーマ色を適用できます。
青花瓷テーマのフォーム
vue
<script setup lang="ts">
import { reactive } from 'vue'
import { LhConfigProvider, LhForm, LhFormItem, LhInput, LhButton } from '@lh-ui/vue3'
const themeForm = reactive({ name: '' })
const cerblueTheme = {
'primary-color': '#2B4C7C',
'primary-color-hover': '#3D649E',
'primary-color-bg': '#E8EDF3',
}
</script>
<template>
<!-- 青花瓷テーマ -->
<LhConfigProvider :theme-vars="cerblueTheme">
<LhForm :model="themeForm" label-width="80px">
<LhFormItem label="氏名">
<LhInput v-model="themeForm.name" />
</LhFormItem>
<LhFormItem>
<LhButton type="primary">送信</LhButton>
</LhFormItem>
</LhForm>
</LhConfigProvider>
</template>vue
<script>
import { LhConfigProvider, LhForm, LhFormItem, LhInput, LhButton } from '@lh-ui/vue3'
export default {
data() {
return {
themeForm: { name: '' },
cerblueTheme: {
'primary-color': '#2B4C7C',
'primary-color-hover': '#3D649E',
'primary-color-bg': '#E8EDF3',
},
}
},
}
</script>
<template>
<!-- 青花瓷テーマ -->
<LhConfigProvider :theme-vars="cerblueTheme">
<LhForm :model="themeForm" label-width="80px">
<LhFormItem label="氏名">
<LhInput v-model="themeForm.name" />
</LhFormItem>
<LhFormItem>
<LhButton type="primary">送信</LhButton>
</LhFormItem>
</LhForm>
</LhConfigProvider>
</template>国際化
国際化フォーム
vue
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { LhConfigProvider, LhForm, LhFormItem, LhInput, LhButton } from '@lh-ui/vue3'
import { jaJP } from '@lh-ui/vue3'
import { enUS } from '@lh-ui/vue3'
const locale = ref('ja-JP')
const formModel = reactive({ name: '' })
</script>
<template>
<!-- 国際化設定 -->
<LhConfigProvider :locale="locale === 'zh-CN' ? zhCN : enUS">
<LhForm :model="formModel" label-width="80px">
<LhFormItem :label="locale === 'zh-CN' ? '姓名' : 'Name'">
<LhInput v-model="formModel.name" :placeholder="locale === 'zh-CN' ? '请输入姓名' : 'Enter name'" />
</LhFormItem>
<LhFormItem>
<LhButton type="primary">{{ locale === 'zh-CN' ? '提交' : 'Submit' }}</LhButton>
</LhFormItem>
</LhForm>
</LhConfigProvider>
</template>vue
<script>
import { LhConfigProvider, LhForm, LhFormItem, LhInput, LhButton } from '@lh-ui/vue3'
import { jaJP } from '@lh-ui/vue3'
import { enUS } from '@lh-ui/vue3'
export default {
data() {
return {
locale: 'ja-JP',
formModel: { name: '' },
jaJP: jaJP,
enUS: enUS,
}
},
}
</script>
<template>
<!-- 国際化設定 -->
<LhConfigProvider :locale="locale === 'zh-CN' ? zhCN : enUS">
<LhForm :model="formModel" label-width="80px">
<LhFormItem :label="locale === 'zh-CN' ? '姓名' : 'Name'">
<LhInput v-model="formModel.name" :placeholder="locale === 'zh-CN' ? '请输入姓名' : 'Enter name'" />
</LhFormItem>
<LhFormItem>
<LhButton type="primary">{{ locale === 'zh-CN' ? '提交' : 'Submit' }}</LhButton>
</LhFormItem>
</LhForm>
</LhConfigProvider>
</template>ラベル位置とインラインレイアウト
label-position でラベルの整列(left / right / top)を切り替え、inline でフォーム項目を水平に並べます。
label-position / inline
vue
<script setup lang="ts">
import { reactive } from 'vue'
const fpModel = reactive({ name: '', city: '' })
</script>
<template>
<LhForm :model="fpModel" label-position="top" inline>
<LhFormItem prop="name" label="名称" required>
<LhInput v-model="fpModel.name" />
</LhFormItem>
<LhFormItem prop="city" label="都市">
<LhInput v-model="fpModel.city" />
</LhFormItem>
</LhForm>
</template>vue
<script>
export default {
data() {
return {
fpModel: { name: '', city: '' },
}
},
}
</script>
<template>
<LhForm :model="fpModel" label-position="top" inline>
<LhFormItem prop="name" label="名称" required>
<LhInput v-model="fpModel.name" />
</LhFormItem>
<LhFormItem prop="city" label="都市">
<LhInput v-model="fpModel.city" />
</LhFormItem>
</LhForm>
</template>LhForm Props
| プロパティ | 説明 | 型 | デフォルト値 |
|---|---|---|---|
| model | フォームデータオブジェクト | { [x: string]: unknown; } | — |
| rules | フィールドのバリデーションルール | { [x: string]: LhFormRule[]; } | — |
| labelPosition | ラベルの位置 | "left" | "right" | "top" | 'right' |
| labelWidth | ラベルの幅 | string | number | — |
| inline | インラインレイアウトにするかどうか | boolean | false |
| sx | sx クイックレイアウトプロパティ | LhSxProps | — |
LhFormItem Props
| プロパティ | 説明 | 型 | デフォルト値 |
|---|---|---|---|
| prop | model に対応するフィールドパス。user.name のような表記をサポート | string | — |
| label | ラベルテキスト | string | — |
| required | 必須かどうか | boolean | false |
| rules | 現在のフィールドのバリデーションルール。Form の rules より優先されます | LhFormRule[] | — |
バリデーションルール
ts
type LhFormRule = {
required?: boolean
message?: string
validator?: (value: unknown, model: Record<string, unknown>) => string | undefined
}LhForm は validate() と resetFields() メソッドを公開しています。
アクセシビリティ
LhFormItemのエラーテキストはrole="alert"を持ち、バリデーション失敗時にスクリーンリーダーが即座に読み上げます- コンテンツ領域は
aria-describedbyでエラーテキストを関連付け、支援技術が「フィールド → エラー」の対応関係を読み取れます。エラーがない場合は関連付けを自動的に削除します - フォームコントロール(Input / Select / Checkbox / Radio / Switch / Slider / InputNumber / DatePicker / TimePicker / Cascader)は所属する
LhFormItemのバリデーション状態を読み取り、失敗時にコントロールへaria-invalidを付け、エラーが解消されると自動的に削除します。コントロールがLhFormItemの外にある場合は影響を受けません - 必須のフォールバックテキストは言語パック
form.required(日本語では「この項目は必須です」)から取得し、ConfigProvider の言語切り替えに追従します。rulesのmessageの方が優先度が高くなります
型定義
このコンポーネントが外部にエクスポートする TypeScript の型構造を以下に示します(packages/components/form/src/types.ts および @lh-ui/share/core/* のソースから自動抽出。各エントリーをクリックすると完全な定義が表示されます。プロパティの説明は上の Props 表を参照してください):
LhFormLabelPosition
ts
export type LhFormLabelPosition = 'left' | 'right' | 'top'LhFormProps
ts
export interface LhFormProps {
model: Record<string, unknown>
rules?: Record<string, LhFormRule[]>
labelPosition?: LhFormLabelPosition
labelWidth?: string | number
inline?: boolean
/** sx クイックレイアウトプロパティ */
sx?: LhSxProps
}LhFormItemProps
ts
export interface LhFormItemProps {
prop?: string
label?: string
required?: boolean
rules?: LhFormRule[]
}LhFormRule (@lh-ui/share/core/form より)
ts
export interface LhFormRule {
required?: boolean
message?: string
validator?: (value: unknown, model: Record<string, unknown>) => string | undefined
}