Table
Simple
| Name | Role | |
|---|---|---|
| NameAlex Morgan | Email[email protected] | RoleOwner |
| NameJamie Lee | Email[email protected] | RoleMember |
| NameRiley Chen | Email[email protected] | RoleMember |
| NameSam Rivera | Email[email protected] | RoleGuest |
open System
open FSharp.ViewEngine
open Acme.Components.Primitives
open Acme.Components.Application
open type Html
open type Svg
open type Datastar
type TeamMember = { id:int; name:string; email:string; role:string }
let teamMembers =
[ { id = 1; name = "Alex Morgan"; email = "[email protected]"; role = "Owner" }; { id = 2; name = "Jamie Lee"; email = "[email protected]"; role = "Member" }; { id = 3; name = "Riley Chen"; email = "[email protected]"; role = "Member" }; { id = 4; name = "Sam Rivera"; email = "[email protected]"; role = "Guest" } ]
let teamColumns =
[ Table.column "Name" (fun (person:TeamMember) -> text person.name) |> Table.asRowHeader
Table.column "Email" (fun person -> text person.email)
Table.column "Role" (fun person -> text person.role) ]
let simpleTeamTable =
Table.create "Team members" teamColumns teamMembers
|> Table.renderComfortable rows
| Name | Role | |
|---|---|---|
| NameAlex Morgan | Email[email protected] | RoleOwner |
| NameJamie Lee | Email[email protected] | RoleMember |
| NameRiley Chen | Email[email protected] | RoleMember |
| NameSam Rivera | Email[email protected] | RoleGuest |
open System
open FSharp.ViewEngine
open Acme.Components.Primitives
open Acme.Components.Application
open type Html
open type Svg
open type Datastar
type TeamMember = { id:int; name:string; email:string; role:string }
let teamMembers =
[ { id = 1; name = "Alex Morgan"; email = "[email protected]"; role = "Owner" }; { id = 2; name = "Jamie Lee"; email = "[email protected]"; role = "Member" }; { id = 3; name = "Riley Chen"; email = "[email protected]"; role = "Member" }; { id = 4; name = "Sam Rivera"; email = "[email protected]"; role = "Guest" } ]
let teamColumns =
[ Table.column "Name" (fun (person:TeamMember) -> text person.name) |> Table.asRowHeader
Table.column "Email" (fun person -> text person.email)
Table.column "Role" (fun person -> text person.role) ]
let comfortableTeamTable =
Table.create "Team members with comfortable rows" teamColumns teamMembers
|> Table.withDensity Density.Comfortable
|> Table.renderWith status values
| Name | Status | |
|---|---|---|
| NameAlex Morgan | Email[email protected] | StatusActive |
| NameJamie Lee | Email[email protected] | StatusActive |
| NameRiley Chen | Email[email protected] | StatusActive |
| NameSam Rivera | Email[email protected] | StatusInvited |
open System
open FSharp.ViewEngine
open Acme.Components.Primitives
open Acme.Components.Application
open type Html
open type Svg
open type Datastar
let memberStatusTable =
Table.create "Team member status" [
Table.column "Name" (fun (name, _, _) -> text name) |> Table.asRowHeader
Table.column "Email" (fun (_, email, _) -> text email)
Table.column "Status" (fun (_, _, status) -> status)
] [
"Alex Morgan", "[email protected]", Status.positive "Active"
"Jamie Lee", "[email protected]", Status.positive "Active"
"Riley Chen", "[email protected]", Status.positive "Active"
"Sam Rivera", "[email protected]", Status.warning "Invited"
]
|> Table.renderWith checkboxes
| Select all | Name | Role | |
|---|---|---|---|
| NameAlex Morgan | Email[email protected] | RoleOwner | |
| NameJamie Lee | Email[email protected] | RoleMember | |
| NameRiley Chen | Email[email protected] | RoleMember | |
| NameSam Rivera | Email[email protected] | RoleGuest |
open System
open FSharp.ViewEngine
open Acme.Components.Primitives
open Acme.Components.Application
open type Html
open type Svg
open type Datastar
type TeamMember = { id:int; name:string; email:string; role:string }
let teamMembers =
[ { id = 1; name = "Alex Morgan"; email = "[email protected]"; role = "Owner" }; { id = 2; name = "Jamie Lee"; email = "[email protected]"; role = "Member" }; { id = 3; name = "Riley Chen"; email = "[email protected]"; role = "Member" }; { id = 4; name = "Sam Rivera"; email = "[email protected]"; role = "Guest" } ]
let teamColumns =
[ Table.column "Name" (fun (person:TeamMember) -> text person.name) |> Table.asRowHeader
Table.column "Email" (fun person -> text person.email)
Table.column "Role" (fun person -> text person.role) ]
let selectableTeamTable =
Table.create "Selectable team members" teamColumns teamMembers
|> Table.withSelection (
TableSelection.create "team-member-selection" (fun person -> string person.id) (fun person -> person.name)
|> TableSelection.withDisabledRows (fun person -> person.role = "Guest")
|> TableSelection.withFormName "memberIds")
|> Table.renderGuest rows are not selectable in this example. Selection covers only the rows on this page.
Stacked on mobile
| Name | Role | |
|---|---|---|
| Alex Morgan | Email[email protected] | RoleOwner |
| Jamie Lee | Email[email protected] | RoleMember |
| Riley Chen | Email[email protected] | RoleMember |
| Sam Rivera | Email[email protected] | RoleGuest |
open System
open FSharp.ViewEngine
open Acme.Components.Primitives
open Acme.Components.Application
open type Html
open type Svg
open type Datastar
type TeamMember = { id:int; name:string; email:string; role:string }
let teamMembers =
[ { id = 1; name = "Alex Morgan"; email = "[email protected]"; role = "Owner" }; { id = 2; name = "Jamie Lee"; email = "[email protected]"; role = "Member" }; { id = 3; name = "Riley Chen"; email = "[email protected]"; role = "Member" }; { id = 4; name = "Sam Rivera"; email = "[email protected]"; role = "Guest" } ]
let mobileTeamTable =
Table.create "Team members as mobile records" [
Table.column "Name" (fun (person:TeamMember) -> text person.name)
|> Table.asRowHeader
|> Table.asMobilePrimary
Table.column "Email" (fun person -> text person.email)
Table.column "Role" (fun person -> text person.role)
] teamMembers
|> Table.withMobileLayout TableMobileLayout.Records
|> Table.renderSortable records
| Name↑ | Role↕ | |
|---|---|---|
| Alex Morgan | Email[email protected] | RoleOwner |
| Jamie Lee | Email[email protected] | RoleMember |
| Riley Chen | Email[email protected] | RoleMember |
| Sam Rivera | Email[email protected] | RoleGuest |
open System
open FSharp.ViewEngine
open Acme.Components.Primitives
open Acme.Components.Application
open type Html
open type Svg
open type Datastar
type TeamMember = { id:int; name:string; email:string; role:string }
let teamMembers =
[ { id = 1; name = "Alex Morgan"; email = "[email protected]"; role = "Owner" }; { id = 2; name = "Jamie Lee"; email = "[email protected]"; role = "Member" }; { id = 3; name = "Riley Chen"; email = "[email protected]"; role = "Member" }; { id = 4; name = "Sam Rivera"; email = "[email protected]"; role = "Guest" } ]
type TeamMemberSort = NameAscending | NameDescending | RoleAscending | RoleDescending
let private teamMemberSortUrl sort direction =
$"/components/table/sort?sort={sort}&direction={direction}"
let private documentSort sort =
sort
|> TableSort.withAttributes [ _dataOn ("click", "evt.preventDefault(); @get(evt.currentTarget.getAttribute('href'))") ]
let private sortFor column current =
match column, current with
| "name", NameAscending -> TableSort.ascending (teamMemberSortUrl "name" "desc") |> documentSort
| "name", NameDescending -> TableSort.descending (teamMemberSortUrl "name" "asc") |> documentSort
| "name", _ -> TableSort.by (teamMemberSortUrl "name" "asc") |> documentSort
| "role", RoleAscending -> TableSort.ascending (teamMemberSortUrl "role" "desc") |> documentSort
| "role", RoleDescending -> TableSort.descending (teamMemberSortUrl "role" "asc") |> documentSort
| "role", _ -> TableSort.by (teamMemberSortUrl "role" "asc") |> documentSort
| _ -> invalidArg (nameof column) "Unsupported team member sort column."
let sortableTeamTable current =
let members =
match current with
| NameAscending -> teamMembers |> List.sortBy _.name
| NameDescending -> teamMembers |> List.sortByDescending _.name
| RoleAscending -> teamMembers |> List.sortBy _.role
| RoleDescending -> teamMembers |> List.sortByDescending _.role
Table.create "Sortable team members" [
Table.column "Name" (fun (person:TeamMember) -> text person.name)
|> Table.asRowHeader
|> Table.asMobilePrimary
|> Table.withSort (sortFor "name" current)
Table.column "Email" (fun person -> text person.email)
Table.column "Role" (fun person -> text person.role)
|> Table.withSort (sortFor "role" current)
] members
|> Table.withMobileLayout TableMobileLayout.Records
|> Table.renderThe application owns the query, destination, and ordered rows. Table only renders the accessible sort controls.
Hierarchical accounts and aggregates
| Account | Type | Total balance (USD) · Current |
|---|---|---|
| Assets | TypeAggregate | Total balance (USD) · Current$184,230.19 |
| Cash | TypeAggregate | Total balance (USD) · Current$96,110.27 |
| Operating checking | TypeAccount | Total balance (USD) · Current$72,104.18 |
| Tax savings | TypeAccount | Total balance (USD) · Current$24,006.09 |
| Accounts receivable | TypeAccount | Total balance (USD) · Current$88,119.92 |
| Liabilities | TypeAggregate | Total balance (USD) · Current−$42,118.44 |
| Business card | TypeAccount | Total balance (USD) · Current−$42,118.44 |
open System
open FSharp.ViewEngine
open Acme.Components.Primitives
open Acme.Components.Application
open type Html
open type Svg
open type Datastar
type HierarchyAccount =
{ key:string
ancestors:string list
level:int
name:string
accountType:string
total:decimal
hasChildren:bool }
let private money amount =
if amount < 0M then $"−${-amount:N2}" else $"${amount:N2}"
let hierarchyAccounts =
[ { key = "assets"; ancestors = []; level = 0; name = "Assets"; accountType = "Aggregate"; total = 184230.19M; hasChildren = true }
{ key = "cash"; ancestors = [ "assets" ]; level = 1; name = "Cash"; accountType = "Aggregate"; total = 96110.27M; hasChildren = true }
{ key = "checking"; ancestors = [ "assets"; "cash" ]; level = 2; name = "Operating checking"; accountType = "Account"; total = 72104.18M; hasChildren = false }
{ key = "savings"; ancestors = [ "assets"; "cash" ]; level = 2; name = "Tax savings"; accountType = "Account"; total = 24006.09M; hasChildren = false }
{ key = "receivables"; ancestors = [ "assets" ]; level = 1; name = "Accounts receivable"; accountType = "Account"; total = 88119.92M; hasChildren = false }
{ key = "liabilities"; ancestors = []; level = 0; name = "Liabilities"; accountType = "Aggregate"; total = -42118.44M; hasChildren = true }
{ key = "card"; ancestors = [ "liabilities" ]; level = 1; name = "Business card"; accountType = "Account"; total = -42118.44M; hasChildren = false } ]
let hierarchicalAccountTable =
Table.create "Account hierarchy"
[ Table.column "Account" (fun row -> a { _href "/components/collection"; _class "font-medium text-[var(--fve-brand-text)]"; row.name })
|> Table.asRowHeader
|> Table.asMobilePrimary
Table.column "Type" (fun row -> text row.accountType)
Table.column "Total balance (USD) · Current" (fun row -> text (money row.total))
|> Table.alignEnd ]
hierarchyAccounts
|> Table.withMobileLayout TableMobileLayout.Records
|> Table.withHierarchy (
TableHierarchy.create "account-hierarchy" _.key (fun row -> row.name) _.ancestors _.level _.hasChildren
|> TableHierarchy.withExpandedKeys [ "assets"; "cash"; "liabilities" ])
|> Table.renderThe consumer supplies every ancestor, level, aggregate value, and destination. Table owns disclosure presentation only.
Empty state
No team members
Team members will appear here when added.
open System
open FSharp.ViewEngine
open Acme.Components.Primitives
open Acme.Components.Application
open type Html
open type Svg
open type Datastar
type TeamMember = { id:int; name:string; email:string; role:string }
let teamColumns =
[ Table.column "Name" (fun (person:TeamMember) -> text person.name) |> Table.asRowHeader
Table.column "Email" (fun person -> text person.email)
Table.column "Role" (fun person -> text person.role) ]
let emptyTeamTable =
Table.create "Empty team members" teamColumns []
|> Table.withEmptyState (
EmptyState.create "No team members" "Team members will appear here when added."
|> EmptyState.render)
|> Table.render