jupiter-dynamic-forms
v1.16.3
Published
Framework-agnostic dynamic form builder for XBRL entrypoints using Web Components. Supports Angular 14+, React, Vue, and vanilla HTML.
Maintainers
Readme
Jupiter Dynamic Forms
Jupiter Dynamic Forms
Framework-agnostic dynamic form builder for XBRL entrypoints using Web Components
Jupiter Dynamic Forms is a powerful, framework-agnostic form builder specifically designed for XBRL (eXtensible Business Reporting Language) data. It automatically generates interactive forms with accordion sections from XBRL taxonomy data, supporting Angular 18+, React, Vue, and vanilla HTML applications.
✨ Key Features
- 🎭 XBRL Integration: Direct consumption of XBRL taxonomy JSON files
- 📱 Framework Agnostic: Works with Angular 18+, React, Vue, or vanilla HTML
- 🎨 Accordion UI: Automatic accordion sections for each presentation role
- 🔍 Role Filtering: Smart filtering for complex forms with 10+ sections
- 💾 Draft Persistence: Automatic localStorage draft saving with full state preservation
- 🔄 Period Preferences: Show/hide concepts by period type (duration/instant) with persistence
- 📅 Previous Year Column: Optional previous year comparison columns per role
- 🏗️ Hierarchical Display: Nested concept trees with proper indentation
- 🔧 Smart Field Types: Automatic mapping from XBRL types to form controls
- 🌐 Multi-language: Intelligent label selection from XBRL labels
- 📊 TypeScript: Full type safety with comprehensive interfaces
- ⚡ Web Components: Built with Lit Element for maximum compatibility
🚀 Quick Start
Installation
npm install @jupiter/dynamic-formsAngular 18+ Integration
// app.module.ts
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import '@jupiter/dynamic-forms';
@NgModule({
// ... other config
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule { }// your-component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-form',
template: `
<jupiter-dynamic-form
[attr.xbrlInput]="xbrlData"
[attr.config]="formConfig"
[attr.language]="language"
[attr.periodStartDate]="periodStart"
[attr.periodEndDate]="periodEnd"
(formSubmit)="onFormSubmit($event)"
(formChange)="onFormChange($event)">
</jupiter-dynamic-form>
`
})
export class FormComponent {
language = 'nl'; // Dutch labels
periodStart = '2024-01-01';
periodEnd = '2024-12-31';
xbrlData = {
presentation: [/* your XBRL data */]
};
formConfig = {
showValidationSummary: true,
collapsibleSections: true
};
onFormSubmit(event: CustomEvent) {
console.log('Form submitted:', event.detail);
}
onFormChange(event: CustomEvent) {
console.log('Form changed:', event.detail);
}
}📊 XBRL Data Structure
Jupiter Dynamic Forms expects XBRL data in JSON format. Each presentation role automatically becomes an accordion section:
- [000001] Filing Information → Company details and registration
- [000101] Profit or Loss Statement → Income statement data
- [000201] Comprehensive Income → Comprehensive income items
- [000301] Financial Position → Balance sheet structure
- [000401] Changes in Equity → Equity movements
- [000501] Cash Flows → Cash flow analysis
🚀 Features
- Framework Agnostic: Works with Angular, React, Vue, and vanilla JavaScript
- JSON Schema Driven: Define complex forms using simple JSON schemas
- XBRL Optimized: Built specifically for XBRL entrypoint data collection
- Accordion Sections: Collapsible sections for better organization
- Nested Concept Trees: Hierarchical data organization with expandable/collapsible nodes
- Tabular Layout: Clean table-based layout with concept trees and input columns
- Dynamic Columns: Add/remove dimension columns on the fly
- Rich Field Types: Support for text, number, date, currency, boolean, select, and more
- Built-in Validation: Comprehensive validation with customizable rules
- TypeScript Support: Full TypeScript definitions included
- Themeable: CSS custom properties for easy styling customization
🔍 Smart Role Filtering (Enhanced in v1.11.0)
For complex XBRL taxonomies with many presentation roles, Jupiter Dynamic Forms provides intelligent filtering:
- Always Available: Filter button always visible for complete user control
- Interactive Dialog: Easy-to-use modal for selecting which roles to display
- Period Preferences: Show/hide duration and instant concepts per role
- Previous Year Column: Optional previous year comparison column per role
- Bulk Actions: "Select All", "Select None", and "Reset" options
- Live Updates: Form sections update immediately when filter is applied
- Role Count Badge: Visual indicator showing selected vs. total roles (e.g., "8/15")
- Preference Persistence: All selections saved automatically to localStorage
// Listen for filter changes
form.addEventListener('roles-filter-changed', (event) => {
const { selectedRoleIds, totalRoles, visibleRoles, periodPreferences } = event.detail;
console.log(`Showing ${visibleRoles} of ${totalRoles} roles`);
console.log('Period preferences:', periodPreferences);
});💾 Draft Persistence (New in v1.11.0)
Automatic draft saving ensures no data loss:
- Automatic Saving: Draft saved to localStorage whenever form data changes
- Full State Preservation: Saves form data, period preferences, selected roles, and custom columns
- Seamless Restoration: Automatically restores draft on page reload
- Smart Validation: Validates draft compatibility with current period dates
- External Storage Support: Supports external draft storage via
dynaformsFactsanddynaformsMetadataproperties - Manual Save: "Save Draft" button for explicit save operations
// Listen for draft save
form.addEventListener('form-save-draft', (event) => {
const { draftData, metadata, saved } = event.detail;
console.log('Draft saved:', saved);
// Optionally save to external storage
await saveToServer(event.detail.dynaformsFacts, event.detail.dynaformsMetadata);
});
// Listen for draft load
form.addEventListener('form-draft-loaded', (event) => {
const { draft, compatible, warnings } = event.detail;
console.log('Draft loaded:', compatible);
if (warnings.length > 0) {
console.warn('Draft compatibility warnings:', warnings);
}
});
// Provide external draft data
form.dynaformsFacts = loadedFactsFromServer;
form.dynaformsMetadata = loadedMetadataFromServer;📦 Installation
npm install @jupiter/dynamic-forms🎯 Quick Start
Vanilla JavaScript / HTML
<!DOCTYPE html>
<html>
<head>
<script type="module">
import '@jupiter/dynamic-forms';
</script>
</head>
<body>
<jupiter-dynamic-form id="my-form"></jupiter-dynamic-form>
<script>
const form = document.getElementById('my-form');
form.schema = {
version: '1.0',
formId: 'example',
title: 'My XBRL Form',
sections: [
// Your schema here
]
};
</script>
</body>
</html>Angular
// app.module.ts
import { JupiterDynamicFormModule } from '@jupiter/dynamic-forms/angular';
@NgModule({
imports: [JupiterDynamicFormModule],
// ...
})
export class AppModule { }<!-- component.html -->
<jupiter-dynamic-form-ng
[schema]="formSchema"
[config]="formConfig"
(formSubmit)="onFormSubmit($event)"
></jupiter-dynamic-form-ng>React
import { JupiterDynamicForm } from '@jupiter/dynamic-forms/react';
function MyComponent() {
const handleSubmit = (data) => {
console.log('Form data:', data);
};
return (
<JupiterDynamicForm
schema={formSchema}
config={formConfig}
onFormSubmit={handleSubmit}
/>
);
}Vue
<template>
<JupiterDynamicForm
:schema="formSchema"
:config="formConfig"
@form-submit="handleSubmit"
/>
</template>
<script>
import { JupiterDynamicForm } from '@jupiter/dynamic-forms/vue';
export default {
components: {
JupiterDynamicForm
},
// ...
}
</script>📋 Schema Structure
The form is driven by a JSON schema that defines sections, concepts, and fields:
{
"version": "1.0",
"formId": "financial-statement",
"title": "Financial Statement Form",
"description": "XBRL financial data entry",
"sections": [
{
"id": "balance-sheet",
"title": "Balance Sheet",
"expanded": true,
"concepts": [
{
"id": "assets",
"name": "Assets",
"label": "Total Assets",
"level": 0,
"fields": [
{
"id": "assets-base",
"conceptId": "assets",
"columnId": "base",
"type": "currency",
"label": "Assets",
"required": true,
"validation": [
{
"type": "required",
"message": "Assets value is required"
}
]
}
],
"children": [
// Nested concepts...
]
}
]
}
]
}🎛️ Configuration Options
const config = {
theme: 'light' | 'dark' | 'auto',
locale: 'en-US',
dateFormat: 'YYYY-MM-DD',
currencyCode: 'USD',
showValidationSummary: true,
collapsibleSections: true,
collapsibleConcepts: true,
enableColumnManagement: true,
maxColumns: 10,
autoSave: false,
autoSaveInterval: 30000
};🔧 Field Types
text- Single line text inputtextarea- Multi-line text inputnumber- Numeric inputdecimal- Decimal number with formattingcurrency- Currency input with formattingpercentage- Percentage inputdate- Date pickerdatetime- Date and time pickerboolean- Checkboxselect- Dropdown selectionmultiselect- Multiple selectionemail- Email input with validationurl- URL input with validationtel- Telephone number input
✅ Validation Rules
required- Field must have a valuemin/max- Numeric range validationminLength/maxLength- String length validationpattern- Regular expression validationemail- Email format validationurl- URL format validationcustom- Custom validation functions
🎨 Styling
The component uses CSS custom properties for theming:
:root {
--jupiter-primary-color: #1976d2;
--jupiter-background: #ffffff;
--jupiter-text-primary: #333333;
--jupiter-border-color: #dddddd;
--jupiter-error-color: #d32f2f;
/* ... more variables */
}📚 API Reference
Properties
| Property | Type | Description |
|----------|------|-------------|
| schema | XBRLFormSchema | The form schema definition |
| xbrlInput | XBRLFormInput | XBRL taxonomy data for automatic schema generation |
| config | ComponentConfig | Configuration options |
| initialData | FormData | Initial form data |
| disabled | boolean | Disable the entire form |
| readonly | boolean | Make form read-only |
| periodStartDate | string | Start date for reporting period (default: '2026-01-01') |
| periodEndDate | string | End date for reporting period (default: '2026-12-31') |
| language | string | ISO language code for XBRL labels (default: 'en', supports 'nl', 'de', etc.) |
| dynaformsFacts | SubmissionData | External draft facts data for restoration |
| dynaformsMetadata | DraftMetadata | External draft metadata for restoration |
| mode | 'input' \| 'admin' | Form mode: 'input' for data entry, 'admin' for role configuration |
| display | 'accordion' \| 'sidePanel' | Layout mode: accordion or side panel with role list |
Methods
| Method | Returns | Description |
|--------|---------|-------------|
| getData() | FormData | Get current form data |
| setData(data) | void | Set form data |
| validate() | boolean | Validate form and return result |
| reset() | void | Reset form to initial state |
| getState() | FormState | Get complete form state |
Events
| Event | Detail | Description |
|-------|--------|-------------|
| field-change | {fieldId, conceptId, columnId, value, oldValue} | Field value changed |
| section-expand | {sectionId, expanded} | Section expanded/collapsed |
| concept-expand | {conceptId, expanded} | Concept expanded/collapsed |
| column-add | {column} | Column added |
| column-remove | {columnId, sectionId} | Column removed |
| form-submit | {data, submissionData, valid, errors} | Form submitted |
| form-save-draft | {draftData, metadata, saved, dynaformsFacts, dynaformsMetadata} | Draft saved |
| form-draft-loaded | {draft, compatible, warnings, source} | Draft loaded from storage |
| roles-filter-changed | {selectedRoleIds, totalRoles, visibleRoles, periodPreferences} | Role filter applied |
| form-reset | {} | Form reset |
🏗️ Development
# Install dependencies
npm install
# Start development server
npm run dev
# Build the library
npm run build
# Run tests
npm test
# Lint code
npm run lint🤝 Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
