Chapter 4.5: Progressive Disclosure with Table Groups
"When users open your domain's Data Sets tab and see 15 tables in a flat list, they are overwhelmed. When they see 6 organized groups with clear icons and descriptions, they know exactly where to go."
The Problem with Flat Lists
Domain templates succeed when users can find what they need quickly. A homeschool co-op domain might have 12 tables: families, students, teachers, classes, enrollments, academic_terms, parents, family_financials, payments, emergency_contacts, medical_info, and field_trips. Each table is valid. Each serves a purpose. But when displayed as a flat alphabetical list in the Data Sets tab, they create cognitive overload.
Which tables are for people versus finances versus events? Which ones do administrators need versus teachers? Where do I start if I want to manage student data?
The platform's progressive disclosure system solves this through table groups — a simple organizational layer that transforms an intimidating flat list into an intuitive navigation structure.
This chapter shows you how to design and implement table groups in your domain configuration, turning your domain from "technically complete" to "delightfully usable."
What Table Groups Do
Table groups organize your domain's tables into logical categories that match how users think about their work. Instead of:
□ academic_terms
□ classes
□ emergency_contacts
□ enrollments
□ families
□ family_financials
□ field_trips
□ medical_info
□ parents
□ payments
□ students
□ teachers
□ volunteer_assignments
Users see:
👥 People
└─ Families, Students, Teachers, Parents
🎓 Classes
└─ Classes, Academic Terms
💰 Financial
└─ Family Financials, Payments
🎪 Events
└─ Field Trips, Volunteer Assignments
🏥 Safety & Health
└─ Emergency Contacts, Medical Info
📊 Reports
└─ Document Templates
The difference is immediate. Users know where to click based on what they want to accomplish, not based on memorizing table names.
Anatomy of a Table Group
A table group in domain-config.json has five properties:
{
"id": "people",
"name": "People",
"icon": "👥",
"description": "Families, students, teachers, and parents",
"tables": ["families", "students", "teachers", "parents"]
}
id: Machine-readable identifier. Lowercase, hyphenated, never changes after publication. This is what the code uses internally.
name: Display label. What users see in the interface. Clear, descriptive, 1-3 words.
icon: Single emoji. Provides instant visual recognition. Choose icons that match your domain's culture — a legal services domain might use ⚖️ for matters, 📋 for documents, 💼 for clients. A property management domain might use 🏢 for buildings, 👥 for tenants, 💰 for financials.
description: Brief summary of what's in this group. This appears as tooltip text when users hover over the group. Not a list of table names — a functional description of what the group helps users do.
tables: Array of table names (matching exactly the names in your tables array). Order matters — this is the sequence they appear when the group is expanded.
Designing Your Table Groups
Table groups are not arbitrary. They should match the natural categories of your domain's work. The process has three steps:
Step 1: List Your Tables by User Intent
Take your complete table list and group them by user intent — what is someone trying to accomplish when they work with this data?
For the legal services domain from Chapter 3:
- Who are we working with? →
firms,clients,attorneys,opposing_counsel - What are we working on? →
matters,practice_areas,case_types - What actions are we tracking? →
hearings,deadlines,depositions,filings - What are we billing? →
billing_entries,invoices,trust_transactions - What documents do we have? →
document_templates(Reports group)
This gives you 5 natural groups: Contacts, Case Management, Court & Deadlines, Financial, Reports.
Step 2: Choose Icons That Tell Stories
Icons are not decoration. They are instant recognition anchors. Choose icons that:
- Match domain culture: Educational domains use 🎓📚✏️. Medical domains use 🏥💊🩺. Legal domains use ⚖️📋💼.
- Are visually distinct: Don't use 📊 and 📈 in the same domain — they look too similar.
- Have universal meaning: 👥 means people everywhere. 💰 means money. 📅 means time/schedule.
- Work in small sizes: Emoji render well at 16px-24px. Avoid emoji with fine detail.
Common icon patterns:
| Domain Category | Good Icon Choices |
|---|---|
| People/Contacts | 👥 👤 👨👩👧👦 📇 |
| Financial | 💰 💵 💳 📊 |
| Scheduling/Events | 📅 🗓️ 🎯 ⏰ |
| Documents/Templates | 📄 📋 📊 📁 |
| Communication | 📧 💬 📞 ✉️ |
| Education/Learning | 🎓 📚 ✏️ 🏫 |
| Healthcare | 🏥 💊 🩺 ❤️ |
| Legal | ⚖️ 📋 💼 🏛️ |
| Real Estate | 🏢 🏠 🏘️ 🔑 |
| Logistics | 📦 🚚 📍 🗺️ |
Step 3: Write Functional Descriptions
Descriptions should answer "What will I accomplish here?" not "What tables are here?"
❌ Bad: "Academic terms and classes"
✅ Good: "Course offerings and schedules"
❌ Bad: "Emergency contacts and medical info tables"
✅ Good: "Emergency and medical information"
❌ Bad: "Families, students, parents"
✅ Good: "Manage student and family records"
Users scan descriptions to confirm they're in the right place. Make that confirmation instant.
Implementation in domain-config.json
Table groups appear as a new top-level property in your domain configuration, immediately after the domain metadata and before the tables array:
{
"domainId": "legal-services",
"domainName": "Legal Services",
"version": "1.0.0",
"description": "Complete document automation for law firms...",
"category": "Professional Services",
"icon": "⚖️",
"tableGroups": [
{
"id": "contacts",
"name": "Contacts",
"icon": "👥",
"description": "Clients, attorneys, and firms",
"tables": ["firms", "clients", "attorneys", "opposing_counsel"]
},
{
"id": "cases",
"name": "Case Management",
"icon": "⚖️",
"description": "Matters and practice areas",
"tables": ["matters", "practice_areas", "case_types"]
},
{
"id": "court",
"name": "Court & Deadlines",
"icon": "📅",
"description": "Hearings, filings, and important dates",
"tables": ["hearings", "deadlines", "depositions", "court_filings"]
},
{
"id": "financial",
"name": "Financial",
"icon": "💰",
"description": "Billing, invoices, and trust accounts",
"tables": ["billing_entries", "invoices", "trust_transactions"]
},
{
"id": "reports",
"name": "Reports",
"icon": "📊",
"description": "Document templates and reports",
"tables": []
}
],
"tables": [
// ... your table definitions
]
}
Notice the Reports group has an empty tables array. This is intentional — the Reports group displays document templates, not data tables. We'll cover that in Chapter 4.6.
Hidden Tables and System Tables
Some tables should not appear in any group — they're junction tables or system tables that users never interact with directly:
{
"tableGroups": [ /* ... */ ],
"hiddenTables": ["enrollments", "trip_participants", "matter_participants"],
"tables": [
{
"name": "enrollments",
"displayName": "Class Enrollments",
"primaryKey": "EnrollmentID",
// ... rest of definition
}
// ... more tables
]
}
The hiddenTables array tells the platform to exclude these tables from all group displays and navigation. They still exist in the data model — they're used for joins and document generation — but users never browse them directly.
Common candidates for hidden tables:
- Junction tables: Many-to-many relationship bridges like
class_enrollments,project_assignments,matter_participants - System tables: Platform-managed tables like
sync_logs,audit_trail,schema_version - Reference tables: Static lookup data like
states,countries,practice_area_codes(unless users need to edit them)
Best Practices
Keep Groups Small
Aim for 4-7 groups total. More than 7 creates the same cognitive load as the original flat list. If you have 8 potential groups, look for opportunities to merge:
- Legal: "Court" + "Deadlines" → "Court & Deadlines"
- Property: "Maintenance" + "Vendors" → "Operations"
- Education: "Classes" + "Teachers" → "Academic"
Make Icons Distinctive
Users will learn to recognize groups by icon alone. Make sure each icon is visually distinct at a glance:
✅ Good: 👥 💰 📅 📊 🏥
❌ Bad: 📊 📈 📉 💹 📋 (all graph/chart-like)
Tables in Order of Common Use
Within each group's tables array, list tables in the order users typically access them:
{
"id": "cases",
"name": "Case Management",
"icon": "⚖️",
"tables": [
"matters", // Most accessed
"practice_areas", // Medium
"case_types" // Least accessed
]
}
Users working through the list from top to bottom should encounter the most important tables first.
Always Include a Reports Group
Every domain should have a Reports group, even if you only have 3 document templates. This creates a consistent navigation pattern across all domains in the marketplace:
{
"id": "reports",
"name": "Reports",
"icon": "📊",
"description": "Document templates and reports",
"tables": []
}
The empty tables array is correct. The Reports group has special rendering logic covered in Chapter 4.6.
Real-World Example: Property Management Domain
Here's a complete table groups configuration for a property management domain:
{
"domainId": "property-management",
"domainName": "Property Management",
"version": "1.0.0",
"description": "Complete property management for residential and commercial properties...",
"category": "Real Estate",
"icon": "🏢",
"tableGroups": [
{
"id": "properties",
"name": "Properties",
"icon": "🏢",
"description": "Buildings, units, and amenities",
"tables": ["buildings", "units", "amenities"]
},
{
"id": "people",
"name": "People",
"icon": "👥",
"description": "Tenants, landlords, and staff",
"tables": ["tenants", "landlords", "property_managers", "maintenance_staff"]
},
{
"id": "leases",
"name": "Leases & Contracts",
"icon": "📋",
"description": "Rental agreements and renewals",
"tables": ["leases", "lease_renewals", "addendums"]
},
{
"id": "financial",
"name": "Financial",
"icon": "💰",
"description": "Rent, payments, and expenses",
"tables": ["rent_payments", "late_fees", "security_deposits", "operating_expenses"]
},
{
"id": "maintenance",
"name": "Maintenance",
"icon": "🔧",
"description": "Work orders and vendor tracking",
"tables": ["maintenance_requests", "work_orders", "vendors", "inspections"]
},
{
"id": "reports",
"name": "Reports",
"icon": "📊",
"description": "Document templates and reports",
"tables": []
}
],
"hiddenTables": ["unit_tenants", "lease_renewals_archive"],
"tables": [
// ... 15-20 table definitions
]
}
This domain has 21 tables total. Without groups, users would face an intimidating alphabetical list from addendums to work_orders. With groups, they navigate confidently: "I need to manage a tenant issue" → People group → tenants table.
Testing Your Table Groups
Before finalizing your groups, validate them with three checks:
1. The 5-Second Test: Show your tableGroups structure to someone unfamiliar with your domain. Can they identify where to find "student contact info" or "vendor payments" within 5 seconds? If not, your groups aren't clear enough.
2. The Coverage Test: Every table in your tables array should either appear in a group or be listed in hiddenTables. No orphans. Run this check:
// Quick validation script
const allTablesInGroups = config.tableGroups.flatMap(g => g.tables);
const allDefinedTables = config.tables.map(t => t.name);
const orphans = allDefinedTables.filter(t =>
!allTablesInGroups.includes(t) &&
!config.hiddenTables.includes(t)
);
if (orphans.length > 0) {
console.error('Orphaned tables:', orphans);
}
3. The Balance Test: No single group should contain more than 40% of your tables. If one group has 8 tables and the rest have 2-3 each, split the large group.
What Happens When Users Click
When a user clicks the "People" group in the Data Sets tab, the platform:
- Expands the group to show its tables as sub-tabs
- Automatically selects the first table in the group's
tablesarray - Displays that table's data in the main view
- Renders action buttons for the selected table (Add, Edit, Delete, Run Report)
- Loads available document templates that use that table as primaryTable
The entire interaction feels instant because the table groups structure tells the platform exactly what to load and in what order.
Migration Strategy for Existing Domains
If you have an existing domain without table groups that's already published to the marketplace, add groups in a minor version update:
- Add the
tableGroupsarray to your domain-config.json - Add any
hiddenTablesyou've identified - Increment version from
1.2.0to1.3.0 - Update your README.md to mention the improved navigation
- Publish the update
Existing users will see the new grouped interface on their next refresh. The data model hasn't changed — only the presentation.
Summary
Table groups are not optional polish. They are the difference between a domain that users struggle to navigate and one they immediately understand.
The implementation is simple: add a tableGroups array to domain-config.json with 4-7 groups, each with an id, name, icon, description, and tables array. The impact is profound: users navigate by intent, not by memorizing table names.
Design your groups based on how users think about their work. Choose icons that create instant visual recognition. Write descriptions that confirm user intent. Keep groups balanced and tables ordered by common use.
With table groups in place, your domain is ready for the next level of user experience: automatic form generation for report parameters. That's Chapter 4.6.