Get started
A Fieldia page is a JSON document. You show it with the viewer, or with the binding for your framework, and you give it a data source that loads and saves records.
Install
Pick the package for your framework. Each one brings the core, the fields and the viewer with it.
npm install @fieldia/viewer # plain JavaScript
npm install @fieldia/react # React 18 or 19
npm install @fieldia/vue # Vue 3
npm install @fieldia/angular # Angular 21 or 22
No bundler? Load the script bundle instead — it sets the global Fieldia. See a script tag below.
A first page
A page names its fields once, then lays them out. This one collects sign-ups, so its data is responses rather than a record:
{
"fieldia": "0.1",
"id": "signup",
"title": "Workshop sign-up",
"data": { "kind": "responses" },
"fields": {
"name": { "type": "char", "label": "Full name", "required": true },
"email": { "type": "char", "label": "Email", "required": true },
"role": {
"type": "selection", "label": "Your role",
"options": [
{ "value": "developer", "label": "Developer" },
{ "value": "other", "label": "Something else" }
]
},
"other_role": { "type": "char", "label": "Which role?" }
},
"layout": {
"type": "sections", "id": "sections",
"children": [{
"type": "section", "id": "you", "columns": 2,
"children": [
{ "type": "field", "id": "name", "field": "name" },
{ "type": "field", "id": "email", "field": "email" },
{ "type": "field", "id": "role", "field": "role", "widget": "radio" },
{ "type": "field", "id": "other_role", "field": "other_role",
"invisible": "role != 'other'", "required": true }
]
}]
}
}
Which role? shows only when someone picks Something else, and it is required only then. The page format describes every part.
Plain JavaScript
import { mountViewer } from '@fieldia/viewer';
import { createMemoryDataSource } from '@fieldia/core';
import page from './signup.page.json';
const viewer = mountViewer(document.getElementById('app'), {
page,
dataSource: createMemoryDataSource(),
skin: 'outlined',
});
mountViewer returns a handle: viewer.form is the live form (values, errors, setValue, subscribe), and viewer.destroy() removes it.
React
import { FieldiaForm } from '@fieldia/react';
export function Signup() {
return <FieldiaForm page={page} dataSource={dataSource} skin="outlined" />;
}
Vue
<script setup lang="ts">
import { FieldiaForm } from '@fieldia/vue';
</script>
<template>
<FieldiaForm :page="page" :data-source="dataSource" skin="outlined" />
</template>
Angular
import { Component } from '@angular/core';
import { FieldiaFormComponent } from '@fieldia/angular';
@Component({
selector: 'app-signup',
imports: [FieldiaFormComponent],
template: `<fieldia-form [page]="page" [dataSource]="dataSource" skin="outlined" />`,
})
export class SignupComponent {
readonly page = page;
readonly dataSource = dataSource;
}
A script tag
For a page with no build step at all. The bundle holds the core, the fields and the viewer — about 60 KB gzipped.
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/@fieldia/viewer/bundle/fieldia.js"></script>
<script>
fetch('/signup.page.json')
.then((response) => response.json())
.then((page) => Fieldia.mountViewer(document.getElementById('app'), {
page,
dataSource: Fieldia.createMemoryDataSource(),
}));
</script>
Next
The memory data source keeps everything in the browser — right for trying things, not for keeping them. Data sources shows how to connect your own backend; Fields lists every field type and how it can be shown.