Skip to content

Form ​

<!-- generated:meta -->

Grupui
Planeresource
Spec structFormSpec

<!-- /generated:meta -->

Kapan Memakai ​

kind: Form adalah override layout input/edit untuk satu Entity — menggantikan form hasil derivasi otomatis.

Kapan memakai Form:

  • Urutan/label/hide field berbeda dari default
  • Grouping field per section (sections), multi-kolom
  • visible_when / readonly_when / required_when / compute (FormSpecExpr)
  • Ubah container: render modal / drawer / separate_page

Kapan TIDAK pakai Form:

  • Entity cukup dengan default → jangan deklarasi Form sama sekali
  • Komposisi multi-entity → kind: Page

Prinsip 3-layer: Form/Table adalah layer tengah antara Entity dan Page. Table = bentuk lain dari Form (sama-sama override di layer yang sama).

Sumber kontrak: docs/spec/frontend/06-page-kinds.md §2.

Contoh Manifest ​

yaml
apiVersion: formspec.dev/v1
kind: Form
metadata:
  name: order-edit
  module: billing
spec:
  public: true
  entity: billing.order
  mode: edit # create | edit | view
  render: { mode: separate_page } # modal | drawer | separate_page
  sections:
    - title: Customer
      columns: 2
      fields:
        - { field: customer_id, widget: relation-picker }
        - { field: member_tier, read_only: true }
    - title: Totals
      fields:
        - {
            field: total,
            read_only: true,
            compute: "sum([i.quantity * i.price for i in fields.items])",
          }
  actions:
    - { action: checkout, label: "Checkout", style: primary }

Atribut ​

<!-- generated:attributes -->

AtributTipeWajibContohDeskripsi
publicboolean—trueIf true (default), a route /module/form/<name> is auto-generated. Set false for embed-only forms.
entitystring✅billing.order
auth_actionenum (login · register · change_password · forgot_password · reset_password)—Bind submit to a platform auth action (mutually exclusive with entity).
modeenum (create · edit · view)—edit
sections[]FormSection—
actions[]FormAction—
submitFormSubmit—
renderFormRenderDecl—
context[]ContextDecl—Context declares render-context variables injected into this form's
confirmFormConfirm—Per-form confirm override: create/update message — nil = inherit App default, empty string = off

<!-- /generated:attributes -->

Render Context (standard slots) ​

Form menerima standard slots fields (nilai form saat ini), route (route.params.*, route.query.*, route.path), dan user (identitas session). Tambahan variabel via context: (closed source set: session, entity, api, const, expr, config).

Auth Forms (auth_action) ​

Form TANPA entity yang mendeklarasikan auth_action (closed set: login | register | change_password | forgot_password | reset_password) me-render custom auth screen pure-YAML: submit di-dispatch ke endpoint /_ui/auth/* (bukan entity CRUD). Nama field memetakan konvensional ke payload auth: username, password, current_password, new_password, email, display_name, token. Sukses login/register → session boot + redirect {route.query.returnTo} (same-origin guard). forgot_password dan reset_password cocok untuk halaman public (Page.public: true).

Tiap field juga mendapat atribut autocomplete konvensional dari pasangan auth_action × nama field: username → username, password pada login → current-password, password pada register/reset_password → new-password, email → email, display_name → name; sisanya off. Tanpa token ini password manager tidak bisa memasangkan, mengisi, atau menyimpan kredensial dengan benar — guidance: Chromium — Create Amazing Password Forms. Karena konvensional, tidak ada properti YAML baru untuk ini.

Gotchas ​

  • Tiap field wajib ada di Entity; tiap action wajib ada + permission-gated otomatis.
  • help mewarisi description entity — FormField.help dan Field.description berarti sama bagi pengguna; help di form hanya perlu ditulis untuk override per-form. Konsekuensinya description entity adalah teks yang dibaca pengguna akhir, bukan catatan desain — detail implementasi ditulis sebagai komentar YAML (# …). help/description hanya tampil di mode create/edit, tidak di mode view, dan tidak di permukaan baca-saja (Table/detail). Section pertama juga mewarisi metadata.description entity sebagai subtitle drawer/dialog (docs/spec/frontend/06-page-kinds.md §2).
  • Vocabulary perilaku client TERTUTUP: visible_when, readonly_when, required_when, compute — butuh efek imperatif → custom widget (asset), bukan FormSpecExpr.
  • Form auth wajib token autocomplete standar (username, current-password, new-password) — jangan "nope" (token tidak valid) atau "off" pada field kredensial; password manager berhenti bisa memasangkan/menyimpan.
  • render = keputusan container design-time, bukan runtime. modal (≤5 field), drawer (5–12), separate_page (12+ field / child table / butuh deep-link). Form kedua dengan render lain = deklarasi terpisah.
  • Validasi server tetap otoritas — rules di client untuk UX, bukan keamanan.
  • public: false → embed-only (no route); hanya tampil di Page authored.
  • Pola UI dipilih dari submit aktif/tidak (bukan characteristic): 2-step+autosave (default), 2-step manual, atau 1-step create-submit.
  • Cross-ref: docs/spec/frontend/06-page-kinds.md §2 · ai_skills/formspec-kinds

Standar terbuka (CC0) dengan implementasi referensi.