メインコンテンツまでスキップ

JSON Schemaパターンサンプル

JSON拡張項目の設定方法

Kurocoのコンテンツ定義では、JSON型の拡張項目を使って柔軟なフォームUIを構築できます。 このページでは、実際に使えるJSON Schemaのパターンを紹介します。

備考

Kurocoで使用するJSONスキーマの構文は、https://json-schema.org/understanding-json-schema/basics に準拠しています。 基本的な構文については公式仕様を参照してください。

基本的なフィールドタイプ

セレクトボックス(文字列の選択)

{
"type": "object",
"properties": {
"status": {
"type": "string",
"title": "ステータス",
"description": "コンテンツの公開状態を選択してください",
"enum": ["draft", "published", "archived"],
"default": "draft"
}
}
}

表示: セレクトボックス

ステータス *
[draft ▼] ← デフォルト値が選択される
- draft
- published
- archived
コンテンツの公開状態を選択してください

注意: defaultが設定されている場合はその値が初期選択されます。


セレクトボックス(表示ラベルのカスタマイズ)

{
"type": "object",
"properties": {
"priority": {
"type": "string",
"title": "優先度",
"enum": ["low", "medium", "high", "urgent"],
"enumNames": ["低", "中", "高", "緊急"],
"default": "medium"
}
}
}

表示: セレクトボックス(日本語ラベル)

優先度
[中 ▼] ← デフォルト値("medium")が選択される
- 低 (value: "low")
- 中 (value: "medium")
- 高 (value: "high")
- 緊急 (value: "urgent")

注意: enumNamesを使用することで、内部的な値(lowなど)とは異なる表示ラベル(など)を設定できます。


セレクトボックス(数値の選択)

{
"type": "object",
"properties": {
"rating": {
"type": "integer",
"title": "評価",
"enum": [1, 2, 3, 4, 5],
"enumNames": ["★", "★★", "★★★", "★★★★", "★★★★★"]
}
}
}

表示: セレクトボックス(数値)

評価
[★ ▼] ← デフォルトで最初の値(1)が選択される
- ★ (value: 1)
- ★★ (value: 2)
- ★★★ (value: 3)
- ★★★★ (value: 4)
- ★★★★★ (value: 5)

注意: Number/Integer型のenumの場合、default未設定時は最初の値が自動選択されます。


複数選択セレクトボックス

{
"type": "object",
"properties": {
"tags": {
"type": "array",
"title": "タグ",
"description": "複数選択可能です(Ctrl/Cmd + クリック)",
"items": {
"type": "string",
"enum": ["技術", "ビジネス", "デザイン", "マーケティング", "その他"]
}
}
}
}

表示: 複数選択セレクトボックス

タグ
[複数選択可能なリスト]
□ 技術
□ ビジネス
□ デザイン
□ マーケティング
□ その他
複数選択可能です(Ctrl/Cmd + クリック)

実用的な入力フォーム

ファイルマネージャー(画像・ファイル選択)

{
"type": "object",
"title": "メディア設定",
"properties": {
"thumbnailImage": {
"type": "string",
"title": "サムネイル画像",
"description": "一覧表示用のサムネイル画像を選択してください",
"format": "file-manager"
},
"headerImage": {
"type": "string",
"title": "ヘッダー画像",
"description": "ページ上部に表示する画像",
"format": "file-manager"
},
"pdfDocument": {
"type": "string",
"title": "PDFドキュメント",
"description": "ダウンロード用PDFファイル",
"format": "file-manager"
},
"videoFile": {
"type": "string",
"title": "動画ファイル",
"format": "file-manager"
}
}
}

表示:

サムネイル画像
[+ ファイルマネージャー] → CKFinder ウィンドウが開く
/files/user/images/thumbnail.jpg [× 削除]
一覧表示用のサムネイル画像を選択してください

ヘッダー画像
[+ ファイルマネージャー] → 既存ファイルを変更
/files/user/images/header.png [× 削除]
ページ上部に表示する画像

PDFドキュメント
[+ ファイルマネージャー]
未設定
ダウンロード用PDFファイル

動画ファイル
[+ ファイルマネージャー]
未設定

特徴:

  • CKFinderとの完全統合
  • ファイルパスを文字列として保存
  • ファイル選択後にプレビューリンク表示

WYSIWYGエディタ(HTMLエディタ)

{
"type": "object",
"title": "記事コンテンツ",
"properties": {
"title": {
"type": "string",
"title": "タイトル",
"minLength": 1,
"maxLength": 100
},
"summary": {
"type": "string",
"title": "要約",
"description": "記事の簡単な説明(プレーンテキスト)",
"format": "textarea",
"rows": 3
},
"content": {
"type": "string",
"title": "本文",
"description": "記事の本文をHTML形式で入力してください",
"format": "html"
},
"sidebarContent": {
"type": "string",
"title": "サイドバーコンテンツ",
"description": "サイドバーに表示する内容",
"format": "html",
"wysiwyg_height": 200,
"wysiwyg_width": "100%"
}
}
}

表示:

タイトル *
[テキスト入力]

要約
[テキストエリア(3行)]
記事の簡単な説明(プレーンテキスト)

本文 *
[CKEditor - WYSIWYGエディタ]
├─ ツールバー: 太字、斜体、リンク、画像、リストなど
├─ ファイルマネージャー統合(画像アップロード可能)
└─ HTMLソース編集可能
記事の本文をHTML形式で入力してください

サイドバーコンテンツ
[CKEditor - WYSIWYGエディタ(高さ200px)]
サイドバーに表示する内容

特徴:

  • format: "html" でCKEditorを自動表示
  • wysiwyg_height: エディタの高さ指定(ピクセル単位)
  • wysiwyg_width: エディタの幅指定(ピクセルまたはパーセンテージ)
  • CKFinderとの完全統合(画像アップロード・管理)

日付・日時の入力

{
"type": "object",
"title": "日付・日時設定",
"properties": {
"publishDate": {
"type": "string",
"title": "公開日",
"description": "記事を公開する日付を選択してください",
"format": "date",
"nullable": false
},
"publishDateTime": {
"type": "string",
"title": "公開日時",
"description": "記事を公開する日時を選択してください",
"format": "date-time",
"nullable": false
},
"eventStartDate": {
"type": ["string", "null"],
"title": "イベント開始日(必須)",
"description": "イベントの開始日を選択してください",
"format": "date"
},
"eventEndDateTime": {
"type": ["string", "null"],
"title": "イベント終了日時(任意)",
"description": "イベントの終了日時を選択してください",
"format": "date-time"
}
}
}

表示例:

公開日
[DatePicker: 📅 YYYY/MM/DD]
記事を公開する日付を選択してください

公開日時
[DatePicker: 📅 YYYY/MM/DD HH:mm:ss]
記事を公開する日時を選択してください

イベント開始日(必須) *
[DatePicker: 📅 YYYY/MM/DD]
イベントの開始日を選択してください

イベント終了日時(任意)
[DatePicker: 📅 YYYY/MM/DD HH:mm:ss]
イベントの終了日時を選択してください

特徴:

  • format: "date": 日付のみ(年月日)を入力
  • format: "date-time": 日付と時刻(年月日 時分秒)を入力
  • nullable: false: 必須項目の表示を設定可能
  • DatePickerコンポーネントで直感的に選択

応用的な設定例

繰り返し項目(配列フォーム)

{
"type": "object",
"properties": {
"news": {
"type": "array",
"title": "ニュース一覧",
"description": "最新のニュースを最大10件まで登録できます",
"minItems": 1,
"maxItems": 10,
"items": {
"type": "object",
"properties": {
"title": {
"type": "string",
"title": "タイトル",
"description": "ニュースのタイトルを入力してください",
"maxLength": 100
},
"link": {
"type": "string",
"title": "リンク",
"description": "ニュース記事のURLを入力してください"
},
"publishDate": {
"type": ["string", "null"],
"title": "公開日",
"format": "date"
},
"category": {
"type": "string",
"title": "カテゴリー",
"enum": ["press", "blog", "event", "update"],
"enumNames": ["プレスリリース", "ブログ", "イベント", "アップデート"]
}
},
"required": ["title", "link"]
}
}
}
}

表示: 繰り返し可能なカードUI

ニュース一覧
[JSON プレビュー] ← クリックでJSON確認(モーダル表示)

最新のニュースを最大10件まで登録できます

┌─────────────────────────────────────────┐
│ ニュース一覧 #1 [↑][↓][× 削除] │
├─────────────────────────────────────────┤
│ タイトル * │
│ [テキスト入力] │
│ ニュースのタイトルを入力してください │
│ │
│ リンク * │
│ [テキスト入力] │
│ ニュース記事のURLを入力してください │
│ │
│ 公開日 │
│ [📅 DatePicker] │
│ │
│ カテゴリー │
│ [-- 選択してください -- ▼] │
│ - プレスリリース │
│ - ブログ │
│ - イベント │
│ - アップデート │
├─────────────────────────────────────────┤
│ [+ ニュース一覧を追加] │
└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│ ニュース一覧 #2 [↑][↓][× 削除] │
├─────────────────────────────────────────┤
│ ... │
├─────────────────────────────────────────┤
│ [+ ニュース一覧を追加] │
└─────────────────────────────────────────┘

特徴:

  • 各アイテムがカード形式で表示
  • ↑↓ボタンで順番を入れ替え可能
  • 各カードの下に「追加」ボタンを配置
  • minItems: 最低限必要なアイテム数(削除時に制限、アラート表示)
  • maxItems: 最大登録可能数(追加時に制限、アラート表示)
  • JSON プレビューボタンで確認可能(モーダル表示、読み取り専用)
  • descriptionは各フィールドの下部に小さな文字で表示

ブログ記事の設定フォーム例

{
"type": "object",
"title": "ブログ記事設定",
"properties": {
"title": {
"type": "string",
"title": "記事タイトル",
"minLength": 1,
"maxLength": 100
},
"category": {
"type": "string",
"title": "カテゴリー",
"enum": ["news", "tutorial", "blog", "announcement"],
"enumNames": ["ニュース", "チュートリアル", "ブログ", "お知らせ"]
},
"status": {
"type": "string",
"title": "公開状態",
"enum": ["draft", "review", "published", "archived"],
"enumNames": ["下書き", "レビュー待ち", "公開済み", "アーカイブ"],
"default": "draft"
},
"featured": {
"type": "boolean",
"title": "注目記事"
},
"tags": {
"type": "array",
"title": "タグ",
"items": {
"type": "string",
"enum": ["Vue.js", "React", "Angular", "JavaScript", "TypeScript", "CSS", "HTML"]
}
},
"visibility": {
"type": "string",
"title": "閲覧権限",
"enum": ["public", "members", "premium", "private"],
"enumNames": ["公開", "会員限定", "プレミアム会員限定", "非公開"],
"default": "public"
},
"publishDate": {
"type": ["string", "null"],
"title": "公開日",
"description": "記事を公開する日付を選択してください",
"format": "date"
},
"publishDateTime": {
"type": ["string", "null"],
"title": "公開日時",
"description": "記事を公開する日時を選択してください",
"format": "date-time"
}
},
"required": ["title", "category", "status"]
}

表示例:

記事タイトル *
[テキスト入力]

カテゴリー *
[セレクトボックス: ニュース / チュートリアル / ブログ / お知らせ]

公開状態 *
[セレクトボックス: 下書き / レビュー待ち / 公開済み / アーカイブ]

注目記事
☑ 有効にする

タグ
[複数選択: Vue.js / React / Angular / ...]

閲覧権限
[セレクトボックス: 公開 / 会員限定 / プレミアム会員限定 / 非公開]

公開日
[DatePicker: 📅 YYYY/MM/DD]
記事を公開する日付を選択してください

公開日時
[DatePicker: 📅 YYYY/MM/DD HH:mm:ss]
記事を公開する日時を選択してください

ECサイト商品設定例

{
"type": "object",
"title": "商品設定",
"properties": {
"productName": {
"type": "string",
"title": "商品名",
"minLength": 1
},
"size": {
"type": "string",
"title": "サイズ",
"enum": ["XS", "S", "M", "L", "XL", "XXL"]
},
"color": {
"type": "string",
"title": "カラー",
"enum": ["red", "blue", "green", "black", "white", "yellow"],
"enumNames": ["レッド", "ブルー", "グリーン", "ブラック", "ホワイト", "イエロー"]
},
"availability": {
"type": "string",
"title": "在庫状況",
"enum": ["in_stock", "low_stock", "out_of_stock", "pre_order"],
"enumNames": ["在庫あり", "残りわずか", "在庫切れ", "予約受付中"],
"default": "in_stock"
},
"shippingOptions": {
"type": "array",
"title": "配送方法",
"items": {
"type": "string",
"enum": ["standard", "express", "overnight", "pickup"],
"enumNames": ["通常配送", "速達", "翌日配送", "店舗受取"]
}
},
"price": {
"type": "number",
"title": "価格",
"minimum": 0
},
"onSale": {
"type": "boolean",
"title": "セール対象"
}
},
"required": ["productName", "price", "availability"]
}

表示例:

商品名 *
[テキスト入力]

サイズ
[セレクトボックス: XS / S / M / L / XL / XXL]

カラー
[セレクトボックス: レッド / ブルー / グリーン / ブラック / ホワイト / イエロー]

在庫状況 *
[セレクトボックス: 在庫あり / 残りわずか / 在庫切れ / 予約受付中]

配送方法
[複数選択: 通常配送 / 速達 / 翌日配送 / 店舗受取]

価格 *
[数値入力]

セール対象
☑ 有効にする

より複雑な配列例(商品バリエーション with WYSIWYG)

{
"type": "object",
"properties": {
"productVariants": {
"type": "array",
"title": "商品バリエーション",
"description": "サイズ・カラー別の商品情報を登録",
"minItems": 1,
"items": {
"type": "object",
"properties": {
"sku": {
"type": "string",
"title": "SKU",
"description": "商品コード"
},
"size": {
"type": "string",
"title": "サイズ",
"enum": ["XS", "S", "M", "L", "XL", "XXL"]
},
"color": {
"type": "string",
"title": "カラー",
"enum": ["red", "blue", "green", "black", "white"],
"enumNames": ["レッド", "ブルー", "グリーン", "ブラック", "ホワイト"]
},
"description": {
"type": "string",
"title": "商品説明",
"description": "このバリエーションの詳細説明",
"format": "html",
"wysiwyg_height": 300
},
"stock": {
"type": "integer",
"title": "在庫数",
"minimum": 0,
"default": 0
},
"price": {
"type": "number",
"title": "価格",
"minimum": 0
},
"image": {
"type": "string",
"title": "商品画像",
"format": "file-manager"
},
"available": {
"type": "boolean",
"title": "販売中",
"default": true
}
},
"required": ["sku", "size", "color", "price"]
}
}
}
}

特徴:

  • 配列オブジェクト内でformat: "html"を使用してWYSIWYGエディタを配置可能
  • 各アイテムごとに独立したCKEditorインスタンスが生成される
  • ファイルマネージャーとWYSIWYGを同時に使用可能
  • wysiwyg_heightで各エディタの高さを個別に調整可能

設定リファレンス

表示モード

  • build_ui_from_schemaが有効 → JSON Schemaに基づいたフォームUIを表示
  • build_ui_from_schemaが無効 → JSONエディタのみ表示

フィールドタイプの自動判定

  • string - テキスト入力
  • string + enum - セレクトボックス
  • string + format: "date" - DatePicker(日付のみ)
  • string + format: "date-time" - DatePicker(日時)
  • string + format: "file-manager" - ファイルマネージャー(CKFinder統合)
  • string + format: "html" - WYSIWYGエディタ(CKEditor)
  • string + format: "textarea" - テキストエリア
  • number / integer - 数値入力
  • number / integer + enum - 数値セレクトボックス
  • boolean - チェックボックス
  • array + items.type: "string" - カンマ区切りテキストエリア
  • array + items.enum - 複数選択セレクトボックス
  • array + items.type: "object" - 繰り返しカードUI
  • object - JSON形式テキストエリア

デフォルト値の決定

  1. defaultが設定されている → その値を使用
  2. defaultが未設定の場合:
    • enumnullが含まれる → nullを初期値とする
    • enumnullが含まれない → enum[0](最初の値)を初期値とする

バリデーション

  • required - 必須項目(Array/Objectタイプ用)
  • nullable - null許可(false時に必須マーク表示、Enum/Date/Number/Integer用)
  • minLength / maxLength - 文字数制限(String用、minLength: 1で必須マーク表示)
  • minimum / maximum - 数値範囲
  • minItems / maxItems - 配列要素数制限
  • pattern - 正規表現パターン

必須項目の設定方法

フィールドを必須項目にする方法は、フィールドタイプによって異なります。

Enum、Date、Date-time、Number、Integerの場合

{
"type": "string", // または "integer", "number"、nullを許可しない
"format": "date", // または "enum": ["1", "2"],
"nullable": false // ← これがfalseの場合に必須マーク表示
}

ルール: nullable: false を設定すると必須マーク(*)が表示されます。typeでnullを許可しないことで入力必須にします。

String(テキスト入力)の場合

{
"type": "string",
"minLength": 1 // ← これが1以上の場合に必須マーク表示
}

ルール: minLength: 1 以上を設定すると必須項目になり、必須マーク(*)が表示されます。

Array(配列)、Object(オブジェクト)の場合

{
"type": "object",
"properties": {
"tags": {
"type": "array",
"minItems": 1, // ← 1つ以上選択必須
"items": {
"type": "string",
"enum": ["1", "2", "3"]
}
}
},
"required": ["tags"] // ← required配列に含まれる場合に必須マーク表示
}

ルール: スキーマのトップレベルにあるrequired配列にフィールド名を含めると必須表示になります。

実践例: 複数タイプの必須項目を含むスキーマ

{
"type": "object",
"properties": {
"status": {
"type": "string", // ← "null"を許可しない
"enum": [null, "draft", "published"],
"nullable": false // ← 必須マーク表示
},
"name": {
"type": "string",
"minLength": 1 // ← 必須マーク表示
},
"publishDate": {
"type": "string", // ← "null"を許可しない
"format": "date",
"nullable": false // ← 必須マーク表示
},
"tags": {
"type": "array",
"minItems": 1, // ← 1つ以上選択必須
"items": {
"type": "string",
"enum": ["1", "2", "3"]
}
}
},
"required": ["tags"] // ← Array/Object以外は各プロパティの設定で必須判定される
}

配列オブジェクトUIの動作

  • アイテム追加時に maxItems チェック(上限に達している場合はアラート表示)
  • アイテム削除時に minItems チェック(最小数を下回る場合はアラート表示)
  • 各カード下部に「追加」ボタンを配置
  • アイテムがゼロの場合は最初の「追加」ボタンのみ表示

その他の機能

  • enumNamesで表示ラベルをカスタマイズ可能
  • type: ["string", "null"]のようなUnion Type(nullable)に対応
  • descriptionはフィールド下部にヘルプテキストとして表示
  • JSON プレビューボタンで現在の値を確認可能(モーダル表示)

ネスト構造の対応状況と制限

サポートされているネスト構造

システムは以下のネスト構造に対応しています:

Object (単一オブジェクト)
{
"type": "object",
"properties": {
"name": {"type": "string"},
"email": {"type": "string"}
}
}
Array → Object (オブジェクトの配列)
{
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {"type": "string"},
"link": {"type": "string"}
}
}
}
Object → Array → Object (オブジェクト内の配列内のオブジェクト)
{
"type": "object",
"properties": {
"news": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {"type": "string"},
"category": {"type": "string", "enum": ["blog", "news"]}
}
}
}
}
}

解説: これらのパターンは完全にサポートされており、UIで直接編集可能です。


制限事項: Array → Object → Array → Object

4階層以上のネスト構造(Array → Object → Array → Object)は、現在UIでの直接編集に対応していません。

対応していない例
{
"type": "object",
"properties": {
"departments": {
"type": "array",
"title": "部署一覧",
"items": {
"type": "object",
"properties": {
"departmentName": {"type": "string", "title": "部署名"},
"employees": {
"type": "array",
"title": "社員一覧",
"items": {
"type": "object",
"properties": {
"employeeName": {"type": "string", "title": "社員名"},
"skills": {
"type": "array",
"title": "スキル一覧",
"items": {
"type": "object",
"properties": {
"skillName": {"type": "string"}
}
}
}
}
}
}
}
}
}
}
}

問題点: departments (Array) → employees (Object → Array) → skills (Object → Array) のような4階層構造は、繰り返しUIの中に繰り返しUIがネストされるため、現在対応していません。


推奨される回避策: 構造を分割する

深いネスト構造が必要な場合は、複数の拡張項目に分割することで対応できます。

解決例: 2つの拡張項目に分割
拡張項目1: departments_data (部署と社員情報)
{
"type": "object",
"properties": {
"departmentId": {
"type": "string",
"title": "部署ID",
"description": "一意の部署識別子"
},
"departmentName": {
"type": "string",
"title": "部署名"
},
"employees": {
"type": "array",
"title": "社員一覧",
"items": {
"type": "object",
"properties": {
"employeeId": {
"type": "string",
"title": "社員ID"
},
"employeeName": {
"type": "string",
"title": "社員名"
},
"position": {
"type": "string",
"title": "役職",
"enum": ["manager","staff","intern"],
"enumNames": ["マネージャー","スタッフ","インターン"
]
}
}
}
}
}
}
拡張項目2: employee_skills_data (社員のスキル情報)
{
"type": "object",
"properties": {
"employeeId": {
"type": "string",
"title": "社員ID",
"description": "departments_dataの社員IDと対応"
},
"employeeName": {
"type": "string",
"title": "社員名(参照用)"
},
"employeeSkills": {
"type": "array",
"title": "社員スキル一覧",
"items": {
"type": "object",
"properties": {
"skillName": {
"type": "string",
"title": "スキル名"
},
"level": {
"type": "string",
"title": "習熟度",
"enum": ["beginner","intermediate","advanced","expert"],
"enumNames": ["初級","中級","上級","エキスパート"]
},
"yearsOfExperience": {
"type": "integer",
"title": "経験年数",
"minimum": 0
}
}
}
}
}
}

メリット:

  • ✅ 各拡張項目が3階層以内(Object → Array → Object)に収まる
  • ✅ UIで完全に編集可能
  • employeeIdをキーとしてデータを関連付け
  • ✅ それぞれのデータを独立して管理できる

データの関連付け:

  • departments_dataで社員の基本情報を管理
  • employee_skills_dataで社員のスキル情報を管理
  • 両者をemployeeIdで紐付け

ネスト構造の対応表

構造パターン階層数UI対応
Object1階層{type: "object"}
Array → Object2階層ニュース一覧、商品バリエーション
Object → Array → Object3階層ユーザー情報 → 注文履歴
Array → Object → Array → Object4階層部署 → 社員 → スキル
それ以上の深いネスト5階層以上-

サポート

お探しのページは見つかりましたか?解決しない場合は、問い合わせフォームからお問い合わせいただくか、Slackコミュニティにご参加ください。