Portals
Dynamic data, user auth, and gated pages combine to create full application experiences — without writing JavaScript. This page walks through complete, copy-pasteable portal examples. Each one includes the data source config, the listing page, and the detail page.
For the core syntax reference, see Dynamic Data. For auth setup, see User Auth & Gating.
How portals work
Every portal on this page is built from the same three layers:
- A listing page shows a collection of records — as cards, a table, or a list. This is the user's dashboard: their orders, projects, listings, whatever the portal is for.
- A detail view shows one record in full. It can be a standalone page with its own URL (
/orders/detail?id=4821) or a modal that opens inline without navigating away. - Auth gating scopes everything to the logged-in user. A
{{currentUser.id}}filter on the data source ensures each person sees only their own records. Putting pages ingated-pages/enforces login.
Detail pages vs detail modals
The detail layer is where portals become useful. Without it, you just have a list. With it, users can drill into any record and see the full picture.
Standalone detail pages get their own URL. Use them when the detail needs to be bookmarkable, shareable, or linkable from an email. An order receipt, a property listing, a member profile — anything a user might want to come back to directly.
data: my-orders
data-display: detail
data-param: id
data-key: id
data-auth: required
data-field: Order Number: order_number
data-field: Status: status
data-field: Total: ${{total}}
data-field: Shipping: {{street}}, {{city}}, {{state}} {{zip}}
The data-param reads a URL query parameter (?id=4821), data-key matches it against a field in the data source, and the page renders that single record.
Detail modals open inline on the same page. Use them for quick-peek details where navigating away would break the flow — scanning a table of support tickets, previewing a product from a grid, checking an order without leaving the dashboard.
data: support-tickets
data-display: table
data-detail: modal
data-field: Subject: subject
data-field: Status: status
data-link: View: #
data-detail-field: Subject: subject
data-detail-field: Priority: priority
data-detail-field: Assigned To: assigned_to
Add data-detail: modal and data-detail-field: lines to any cards, list, or table block. Clicking the link opens the modal with the full record — no separate page needed.
Combining both on one page
A single page can have multiple data blocks. A project detail page can show the project record as a detail view at the top and its invoices as a table with modal details below it. Every example on this page demonstrates this kind of composition.
Freelancer client portal
A freelancer shares project status, invoices, and files with each client. Every client logs in and sees only their own projects. Each project links to a detail page with deliverables, timeline, and an invoice download.
Data sources
# settings/data.md
sources:
- name: client-projects
table: projects
select: id, name, status, start_date, due_date, budget, thumbnail_url, slug
filter: client_id = {{currentUser.id}}
sort: due_date desc
- name: project-invoices
table: invoices
select: id, invoice_number, amount, status, issued_date, pdf_url, project_id
filter: client_id = {{currentUser.id}}
sort: issued_date desc
Projects list
The client's dashboard — shows all their active and completed projects as cards.
File: gated-pages/projects.md
---
title: My Projects
slug: /account/projects
---
data: client-projects
data-display: cards
data-auth: required
data-title: name
data-text: {{status}} · Due {{due_date}}
data-image: thumbnail_url
data-link: View Project: /account/projects/detail?slug={{slug}}
Project detail
Each project gets its own page with full specs, timeline, and a list of invoices.
File: gated-pages/projects/detail.md
data: client-projects
data-display: detail
data-param: slug
data-key: slug
data-auth: required
data-field: Project: name
data-field: Status: status
data-field: Started: start_date
data-field: Due: due_date
data-field: Budget: {{budget}}
Below the project detail, show invoices for that project:
data: project-invoices
data-display: table
data-auth: required
data-filter: project_id = {{param.id}}
data-field: Invoice: invoice_number
data-field: Amount: {{amount}}
data-field: Status: status
data-field: Issued: issued_date
data-link: Download PDF: {{pdf_url}}
SaaS admin panel
An admin dashboard for a SaaS product. Team members manage users, view subscription metrics, and handle support tickets. Different user types see different views.
Data sources
# settings/data.md
sources:
- name: team-users
table: users
select: id, email, name, avatar_url, plan, status, created_at, last_login
sort: created_at desc
- name: support-tickets
table: tickets
select: id, subject, requester_email, status, priority, created_at, assigned_to
sort: created_at desc
- name: subscriptions
table: subscriptions
select: id, user_email, plan, amount, interval, status, next_billing, started_at
sort: next_billing asc
User management
File: gated-pages/admin/users.md
---
title: Users
slug: /admin/users
gated: admin
---
data: team-users
data-display: table
data-auth: required
data-field: Name: name
data-field: Email: email
data-field: Plan: plan
data-field: Status: status
data-field: Joined: created_at
data-link: View: /admin/users/detail?id={{id}}
data-paginate: true
data-limit: 25
User detail
File: gated-pages/admin/users/detail.md
data: team-users
data-display: detail
data-param: id
data-key: id
data-auth: required
data-field: Name: name
data-field: Email: email
data-field: Plan: plan
data-field: Status: status
data-field: Joined: created_at
data-field: Last Login: last_login
Support tickets
File: gated-pages/admin/tickets.md
data: support-tickets
data-display: table
data-auth: required
data-detail: modal
data-field: Subject: subject
data-field: From: requester_email
data-field: Priority: priority
data-field: Status: status
data-field: Created: created_at
data-link: View: #
data-detail-field: Subject: subject
data-detail-field: From: requester_email
data-detail-field: Priority: priority
data-detail-field: Status: status
data-detail-field: Assigned To: assigned_to
data-detail-field: Created: created_at
data-filter: status != closed
data-sort: priority desc
| Subject | From | Priority | Status | Created | |
|---|---|---|---|---|---|
| Can't export CSV from dashboard | alice@example.com | High | Open | 2026-03-23 | View |
| Billing page shows wrong amount | ben@example.com | High | In Progress | 2026-03-22 | View |
| Feature request: dark mode | david@example.com | Low | Open | 2026-03-20 | View |
| SSO setup not working | eva@example.com | Medium | Open | 2026-03-19 | View |
Role-based access
Gate different admin sections by user type in your page frontmatter:
# Full admin access
gated: admin
# Support team only
gated: admin, support
# View-only for managers
gated: admin, manager
See User Types for how to define and assign user types.
Real estate listings portal
A property listing site where agents publish listings and buyers browse. Public listing cards, detailed property pages, and a gated agent dashboard for managing listings.
Data sources
# settings/data.md
sources:
- name: listings
table: properties
select: id, address, city, state, price, beds, baths, sqft, photo_url, slug, status, listed_date
filter: status = active
sort: listed_date desc
- name: my-listings
table: properties
select: id, address, city, price, status, views, inquiries, listed_date, slug
filter: agent_id = {{currentUser.id}}
sort: listed_date desc
Public property browse
This page is public — no login required. Visitors browse active listings as cards.
File: pages/properties.md
---
title: Properties for Sale
slug: /properties
---
data: listings
data-display: cards
data-title: address
data-text: {{city}}, {{state}} · {{beds}} bd / {{baths}} ba · {{sqft}} sqft
data-image: photo_url
data-link: ${{price}}: /properties/detail?slug={{slug}}
data-limit: 12
data-paginate: true
Property detail
File: pages/properties/detail.md
data: listings
data-display: detail
data-param: slug
data-key: slug
data-field: Address: address
data-field: Location: {{city}}, {{state}}
data-field: Price: ${{price}}
data-field: Bedrooms: beds
data-field: Bathrooms: baths
data-field: Square Feet: sqft
data-field: Status: status
data-field: Listed: listed_date
Agent dashboard
Logged-in agents see their own listings with performance metrics.
File: gated-pages/agent/listings.md
data: my-listings
data-display: table
data-auth: required
data-field: Address: address
data-field: City: city
data-field: Price: ${{price}}
data-field: Status: status
data-field: Views: views
data-field: Inquiries: inquiries
data-link: Details: #
data-detail: modal
data-detail-field: Address: address
data-detail-field: City: city
data-detail-field: Price: ${{price}}
data-detail-field: Status: status
data-detail-field: Views: views
data-detail-field: Inquiries: inquiries
data-detail-field: Listed: listed_date
Membership directory
A professional community with public member profiles and private member-only features. Members browse the directory, view profiles, and access gated resources.
Data sources
# settings/data.md
sources:
- name: members
table: members
select: id, name, title, company, avatar_url, bio, location, website, slug
filter: visibility = public
sort: name asc
- name: member-resources
table: resources
select: id, title, description, category, file_url, created_at
sort: created_at desc
Member directory
Public directory showing all visible members.
File: pages/members.md
data: members
data-display: cards
data-title: name
data-text: {{title}} at {{company}}
data-image: avatar_url
data-link: View Profile: /members/profile?slug={{slug}}
data-paginate: true
data-limit: 24
Member profile
File: pages/members/profile.md
data: members
data-display: detail
data-param: slug
data-key: slug
data-field: Name: name
data-field: Title: title
data-field: Company: company
data-field: Location: location
data-field: Bio: bio
data-field: Website: website
Gated resources
Members-only resource library, visible after login.
File: gated-pages/resources.md
data: member-resources
data-display: list
data-auth: required
data-title: title
data-text: {{category}} · {{description}}
data-link: Download: {{file_url}}
-
2026 Industry Salary Report
Research · Comprehensive salary data across 12 engineering roles and 40 metro areas
-
Startup Fundraising Playbook
Guide · Seed to Series B — term sheets, pitch decks, and investor outreach templates
-
Remote Team Toolkit
Template · Async standup templates, decision logs, and meeting-free week schedules
E-commerce customer account
A customer account area for an online store. Order history, saved addresses, and wishlist — all filtered to the logged-in user.
Data sources
# settings/data.md
sources:
- name: my-orders
table: orders
select: id, order_number, status, total, item_count, created_at, tracking_url
filter: customer_id = {{currentUser.id}}
sort: created_at desc
- name: my-addresses
table: addresses
select: id, label, street, city, state, zip, is_default
filter: customer_id = {{currentUser.id}}
sort: is_default desc
- name: my-wishlist
table: wishlist_items
select: id, product_name, product_image, product_price, product_slug, added_at
filter: customer_id = {{currentUser.id}}
sort: added_at desc
Order history
File: gated-pages/account/orders.md
data: my-orders
data-display: table
data-auth: required
data-detail: modal
data-field: Order: order_number
data-field: Items: item_count
data-field: Total: ${{total}}
data-field: Status: status
data-field: Date: created_at
data-link: Details: #
data-detail-field: Order Number: order_number
data-detail-field: Status: status
data-detail-field: Total: ${{total}}
data-detail-field: Items: item_count
data-detail-field: Tracking: tracking_url
data-paginate: true
Wishlist
File: gated-pages/account/wishlist.md
data: my-wishlist
data-display: cards
data-auth: required
data-title: product_name
data-text: ${{product_price}}
data-image: product_image
data-link: View Product: /products/detail?slug={{product_slug}}
Saved addresses
File: gated-pages/account/addresses.md
data: my-addresses
data-display: list
data-auth: required
data-title: label
data-text: {{street}}, {{city}}, {{state}} {{zip}}
-
Home (Default)
742 Evergreen Terrace, Springfield, IL 62704
-
Office
100 Industrial Way, Suite 400, Springfield, IL 62711
Building your own portal
Every example on this page follows the same pattern:
- Define data sources in
settings/data.md— one per collection, with{{currentUser.id}}filters for user-scoped data - Create listing pages with
data-display: cards,list, ortable— put them ingated-pages/if they require login - Create detail pages with
data-display: detailanddata-param/data-keyfor URL-based record lookup - Gate by user type with
gated: admin, memberin frontmatter for role-based access
Mix and match display modes on the same page. A project detail page can show the project record as a detail view and its invoices as a table below it. A course page can show the course info as detail fields and its lessons as a list.
The data sources, display modes, and auth gating are all documented in detail: