Skip to content
bahtuiv0.18.8
bank20baht-ui 0.18.8

JSON in, form out.

A form and workflow engine shipped as Web Components. Describe the form as JSON, render it from React, Vue, Angular or plain HTML.

Live<baht-form>
The JSON behind it
{
  "form_id": "quote",
  "form_name": "Request a quote",
  "fields": [
    {
      "order": 1,
      "type": "text",
      "key": "company",
      "label": "Company",
      "width": "1/2",
      "required": true,
      "value": "Siam Paper Co."
    },
    {
      "order": 2,
      "type": "email",
      "key": "email",
      "label": "Email",
      "width": "1/2",
      "value": "malee@siampaper.co"
    },
    {
      "order": 3,
      "type": "dropdown",
      "key": "plan",
      "label": "Plan",
      "width": "1/2",
      "options": [
        {
          "key": "free",
          "label": "Free"
        },
        {
          "key": "team",
          "label": "Team"
        },
        {
          "key": "enterprise",
          "label": "Enterprise"
        }
      ],
      "value": "team"
    },
    {
      "order": 4,
      "type": "number",
      "key": "seats",
      "label": "Seats",
      "width": "1/2",
      "min": 1,
      "max": 500,
      "value": 12
    },
    {
      "order": 5,
      "type": "toggle",
      "key": "invoice",
      "label": "Invoice monthly",
      "width": "1/1",
      "value": true
    }
  ]
}

JSON เข้า ฟอร์มออก

เขียนฟอร์มเป็น JSON ชิ้นเดียว ได้ UI จริงทันที ไม่ต้องเขียน component เอง

bahtui
{
"form_name": "signup",
"fields": [
{ "type": "text", "key": "name",
"label": "Full name", "required": true },
{ "type": "email", "key": "email",
"label": "Work email", "required": true },
{ "type": "dropdown", "key": "plan",
"options": ["starter", "team", "enterprise"] },
{ "type": "range", "key": "seats",
"min": 1, "max": 50 },
{ "type": "rating", "key": "fit" }
]
}
{
"forms": [
{ "form_name": "Request", "fields": […] },
{ "form_name": "Details", "fields": […] },
{ "form_name": "Approval", "kind": "approval" }
],
"rules": [{
"when": { "field": "Request.kind",
"op": "eq", "value": "travel" },
"then": [{ "action": "show",
"target": { "field": "destination" } }],
"else": [{ "action": "hide", … }]
}]
}
server.ts
import { validateSubmission } from 'bank20baht-validator';
app.post('/submit', ({ body }) => {
const result = validateSubmission(schema, body.data);
if (!result.valid) return status(422, result.issues);
return save(result.data); // rules re-run, hidden fields cleared
});
POST /submit  { "plan": "team", "seats": 12, … }

One import registers every element

The bundle defines the custom elements, the stylesheet ships the tokens, and the engine is a pure TypeScript module you can run on the server too.

setup.ts
npm i bank20baht-ui
import 'bank20baht-ui'; // registers every <baht-*> element
import 'bank20baht-ui/tokens.css'; // design tokens: override any --baht-* to theme
import { evaluate } from 'bank20baht-ui/engine'; // headless rules engine, no DOM

Two levels of use

One controlled form

You own all state. The element renders the fields, emits changes and validity, and nothing else.

<baht-form></baht-form>
<script>
document.querySelector('baht-form').form = {
form_id: 'f1', form_name: 'Person',
fields: [
{ order: 1, type: 'text', key: 'first_name',
label: 'First name', width: '1/2', required: true }
]
};
</script>

A rules-driven wizard

Several forms as steps, plus rules that show, hide, skip and compute across them.

<baht-workflow></baht-workflow>
<script>
document.querySelector('baht-workflow').workflow = {
workflow_id: 'onboarding',
forms: [ /* one form per step */ ],
rules: [ { when: 'plan == "team"', show: ['seats'] } ]
};
</script>

Where to next