SGUI / Development
AppDataGrid
Owned selection, sorting, filtering, columns and paging.
Loading examples…
Loading examples…
Examples
Loading examples…
Component documentation
SGUI / Development
Owned selection, sorting, filtering, columns and paging.
Loading examples…
Loading examples…
Loading examples…
Course | Status | Score | Action | |
|---|---|---|---|---|
Course 1 | archived | 100 | ||
Course 2 | active | 97 | ||
Course 3 | active | 94 | ||
Course 4 | archived | 91 | ||
Course 5 | active | 88 | ||
Course 6 | active | 85 | ||
Course 7 | archived | 82 | ||
Course 8 | active | 79 | ||
Course 9 | active | 76 | ||
Course 10 | archived | 73 | ||
Course 11 | active | 70 | ||
Course 12 | active | 67 | ||
Course 13 | archived | 64 | ||
Course 14 | active | 61 | ||
Course 15 | active | 58 | ||
Course 16 | archived | 55 | ||
Course 17 | active | 52 | ||
Course 18 | active | 49 |
Course | Status | Score | Action | |
|---|---|---|---|---|
Course 1 | archived | 100 | ||
Course 2 | active | 97 | ||
Course 3 | active | 94 | ||
Course 4 | archived | 91 | ||
Course 5 | active | 88 | ||
Course 6 | active | 85 | ||
Course 7 | archived | 82 | ||
Course 8 | active | 79 | ||
Course 9 | active | 76 | ||
Course 10 | archived | 73 | ||
Course 11 | active | 70 | ||
Course 12 | active | 67 | ||
Course 13 | archived | 64 | ||
Course 14 | active | 61 | ||
Course 15 | active | 58 | ||
Course 16 | archived | 55 | ||
Course 17 | active | 52 | ||
Course 18 | active | 49 |
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import { Button, AppDataGrid, AppDataGridShell, CourseCardFrame, createDataGridColumns, createActionMenuColumn, type AppDataGridColumn, type AppDataGridRowDragReorderParams } from '@structured-growth/sg-ui/components';
import { Stack, Typography, Link } from '@structured-growth/sg-ui/primitives';
export default function DataGridExample() {
type Course={id:string;name:string;status:string;score:number};
const [rows,setRows]=useState<Course[]>([{"id":"1","name":"Course 1","status":"archived","score":100},{"id":"2","name":"Course 2","status":"active","score":97},{"id":"3","name":"Course 3","status":"active","score":94},{"id":"4","name":"Course 4","status":"archived","score":91},{"id":"5","name":"Course 5","status":"active","score":88},{"id":"6","name":"Course 6","status":"active","score":85},{"id":"7","name":"Course 7","status":"archived","score":82},{"id":"8","name":"Course 8","status":"active","score":79},{"id":"9","name":"Course 9","status":"active","score":76},{"id":"10","name":"Course 10","status":"archived","score":73},{"id":"11","name":"Course 11","status":"active","score":70},{"id":"12","name":"Course 12","status":"active","score":67},{"id":"13","name":"Course 13","status":"archived","score":64},{"id":"14","name":"Course 14","status":"active","score":61},{"id":"15","name":"Course 15","status":"active","score":58},{"id":"16","name":"Course 16","status":"archived","score":55},{"id":"17","name":"Course 17","status":"active","score":52},{"id":"18","name":"Course 18","status":"active","score":49}]);
const [message,setMessage]=useState("");
const [search,setSearch]=useState("");
const [view,setView]=useState<'list'|'cards'>("list");
const columns:AppDataGridColumn<Course>[] = createDataGridColumns([{field:'name',headerName:'Course',flex:2,minWidth:180,locked:true,truncate:true},{field:'status',headerName:'Status',width:140,filterType:'enum'},{field:'score',headerName:'Score',width:120,filterType:'number'},createActionMenuColumn<Course>({getMenuActions:row=>[{id:'open',label:'Open course',onPress:()=>setMessage(`Opened ${row.name}`)}]})]);
return (
<>
<ThemeScope density="comfortable">
<Stack gap={3}><AppDataGrid label={"Courses"} rows={rows} columns={columns} getRowLabel={row=>row.name} selection={true} searchValue={search} onSearchChange={setSearch} pageSizeOptions={[25,50,100]} defaultPaginationModel={{page:0,pageSize:25}} hideFooter={false} filterFields={[{"id":"status","label":"Status","type":"enum","enumOptions":[{"id":"active","label":"Active"},{"id":"archived","label":"Archived"}]}]} loading={false} refreshing={false} errorMessage={undefined} onRetry={()=>setMessage('Retry requested')} showResetView={true} style={{height:"max-content",flex:"none"}}/>{message && <Typography role="status">{message}</Typography>}</Stack>
</ThemeScope>
</>
);
}
Both columns display the same long course name at equal widths. The first wraps onto multiple lines; the second stays on one line with an ellipsis. Activate a row to see the host callback result; your application supplies navigation.
Wrapped text | Truncated text | |
|---|---|---|
Foundations of accessible learning experiences and inclusive course design | Foundations of accessible learning experiences and inclusive course design | |
Practical workshop on building accessible activities and providing meaningful learner feedback | Practical workshop on building accessible activities and providing meaningful learner feedback | |
Leading collaborative projects across distributed learning teams | Leading collaborative projects across distributed learning teams |
'use client';
import { useState } from 'react';
import { AppDataGrid, AppDataGridShell, type AppDataGridColumn } from '@structured-growth/sg-ui/components';
import { Stack, Typography, Link } from '@structured-growth/sg-ui/primitives';
export default function MultilineGridExample() {
type Row={id:string;name:string};
const rows:Row[]=[{"id":"foundations","name":"Foundations of accessible learning experiences and inclusive course design"},{"id":"practice","name":"Practical workshop on building accessible activities and providing meaningful learner feedback"},{"id":"leadership","name":"Leading collaborative projects across distributed learning teams"}];
const [message,setMessage]=useState("");
const columns:AppDataGridColumn<Row>[]=[
{field:'name',headerName:'Wrapped text',flex:1,minWidth:200,truncate:false,locked:true},
{field:'truncated',headerName:'Truncated text',getCellValue:row=>row.name,flex:1,minWidth:200,truncate:true},
];
return (
<>
<Stack gap={3}>
<AppDataGrid label="Courses with wrapped text" rows={rows} columns={columns} getRowLabel={row=>row.name} onRowAction={row=>setMessage('Opened '+row.name)} hideFooter style={{height:"max-content",flex:"none"}}/>
{message && <Typography role="status">{message}</Typography>}
</Stack>
</>
);
}
A fixed reference configuration with its own row interactions and host feedback.
Course | Status | |
|---|---|---|
Course 1 | archived | |
Course 2 | active | |
Course 3 | active | |
Course 4 | archived | |
Course 5 | active | |
Course 6 | active |
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import { AppDataGrid, AppDataGridShell, CourseCardFrame, type AppDataGridColumn } from '@structured-growth/sg-ui/components';
import { Stack, Typography, Link } from '@structured-growth/sg-ui/primitives';
export default function GridReferenceExample() {
type Course={id:string;name:string;status:string;score:number};
const rows:Course[]=[{"id":"1","name":"Course 1","status":"archived","score":100},{"id":"2","name":"Course 2","status":"active","score":97},{"id":"3","name":"Course 3","status":"active","score":94},{"id":"4","name":"Course 4","status":"archived","score":91},{"id":"5","name":"Course 5","status":"active","score":88},{"id":"6","name":"Course 6","status":"active","score":85}];
const columns:AppDataGridColumn<Course>[]=[{"field":"name","headerName":"Course","flex":1,"minWidth":180,"locked":true},{"field":"status","headerName":"Status","width":100}];
const [message,setMessage]=useState("No reference action yet");
return (
<>
<ThemeScope density="compact">
<Stack gap={3}>
<AppDataGrid label={"List · compact"} rows={rows} columns={columns} getRowId={row=>row.id} getRowLabel={row=>row.name} defaultPaginationModel={{page:0,pageSize:6}} pageSizeOptions={[6,10]} loading={false} refreshing={false} errorMessage={undefined} onRetry={()=>setMessage('Retry requested')} onRowAction={row=>setMessage('Opened '+row.name)} style={{height:"max-content",flex:"none"}}/>
</Stack>
</ThemeScope>
</>
);
}
A fixed reference configuration with its own row interactions and host feedback.
Course | Status | |
|---|---|---|
Course 1 | archived | |
Course 2 | active | |
Course 3 | active | |
Course 4 | archived | |
Course 5 | active | |
Course 6 | active |
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import { AppDataGrid, AppDataGridShell, CourseCardFrame, type AppDataGridColumn } from '@structured-growth/sg-ui/components';
import { Stack, Typography, Link } from '@structured-growth/sg-ui/primitives';
export default function GridReferenceExample() {
type Course={id:string;name:string;status:string;score:number};
const rows:Course[]=[{"id":"1","name":"Course 1","status":"archived","score":100},{"id":"2","name":"Course 2","status":"active","score":97},{"id":"3","name":"Course 3","status":"active","score":94},{"id":"4","name":"Course 4","status":"archived","score":91},{"id":"5","name":"Course 5","status":"active","score":88},{"id":"6","name":"Course 6","status":"active","score":85}];
const columns:AppDataGridColumn<Course>[]=[{"field":"name","headerName":"Course","flex":1,"minWidth":180,"locked":true},{"field":"status","headerName":"Status","width":100}];
const [message,setMessage]=useState("No reference action yet");
return (
<>
<ThemeScope density="comfortable">
<Stack gap={3}>
<AppDataGrid label={"List · comfortable"} rows={rows} columns={columns} getRowId={row=>row.id} getRowLabel={row=>row.name} defaultPaginationModel={{page:0,pageSize:6}} pageSizeOptions={[6,10]} loading={false} refreshing={false} errorMessage={undefined} onRetry={()=>setMessage('Retry requested')} onRowAction={row=>setMessage('Opened '+row.name)} style={{height:"max-content",flex:"none"}}/>
</Stack>
</ThemeScope>
</>
);
}
Initial loading: no rows have arrived yet.
Course | Status | |
|---|---|---|
Loading rows | ||
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import { AppDataGrid, AppDataGridShell, CourseCardFrame, type AppDataGridColumn } from '@structured-growth/sg-ui/components';
import { Stack, Typography, Link } from '@structured-growth/sg-ui/primitives';
export default function GridReferenceExample() {
type Course={id:string;name:string;status:string;score:number};
const rows:Course[]=[];
const columns:AppDataGridColumn<Course>[]=[{"field":"name","headerName":"Course","flex":1,"minWidth":180,"locked":true},{"field":"status","headerName":"Status","width":100}];
const [message,setMessage]=useState("No reference action yet");
return (
<>
<ThemeScope density="comfortable">
<Stack gap={3}>
<AppDataGrid label={"Loading dataset · comfortable"} rows={rows} columns={columns} getRowId={row=>row.id} getRowLabel={row=>row.name} defaultPaginationModel={{page:0,pageSize:6}} pageSizeOptions={[6,10]} loading={true} refreshing={false} errorMessage={undefined} onRetry={()=>setMessage('Retry requested')} onRowAction={row=>setMessage('Opened '+row.name)} style={{height:"max-content",flex:"none"}}/>
</Stack>
</ThemeScope>
</>
);
}
Existing rows remain in place during refresh, with busy semantics and a polite announcement. Standalone hosts can compose DataToolbar to show refresh progress.
Course | Status | |
|---|---|---|
Course 1 | archived | |
Course 2 | active | |
Course 3 | active | |
Course 4 | archived | |
Course 5 | active | |
Course 6 | active |
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import { AppDataGrid, AppDataGridShell, CourseCardFrame, type AppDataGridColumn } from '@structured-growth/sg-ui/components';
import { Stack, Typography, Link } from '@structured-growth/sg-ui/primitives';
export default function GridReferenceExample() {
type Course={id:string;name:string;status:string;score:number};
const rows:Course[]=[{"id":"1","name":"Course 1","status":"archived","score":100},{"id":"2","name":"Course 2","status":"active","score":97},{"id":"3","name":"Course 3","status":"active","score":94},{"id":"4","name":"Course 4","status":"archived","score":91},{"id":"5","name":"Course 5","status":"active","score":88},{"id":"6","name":"Course 6","status":"active","score":85}];
const columns:AppDataGridColumn<Course>[]=[{"field":"name","headerName":"Course","flex":1,"minWidth":180,"locked":true},{"field":"status","headerName":"Status","width":100}];
const [message,setMessage]=useState("No reference action yet");
return (
<>
<ThemeScope density="comfortable">
<Stack gap={3}>
<AppDataGrid label={"Refreshing dataset · comfortable"} rows={rows} columns={columns} getRowId={row=>row.id} getRowLabel={row=>row.name} defaultPaginationModel={{page:0,pageSize:6}} pageSizeOptions={[6,10]} loading={false} refreshing={true} errorMessage={undefined} onRetry={()=>setMessage('Retry requested')} onRowAction={row=>setMessage('Opened '+row.name)} style={{height:"max-content",flex:"none"}}/>
</Stack>
</ThemeScope>
</>
);
}
A fixed reference configuration with its own row interactions and host feedback.
Course | Status | |
|---|---|---|
No rows available | ||
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import { AppDataGrid, AppDataGridShell, CourseCardFrame, type AppDataGridColumn } from '@structured-growth/sg-ui/components';
import { Stack, Typography, Link } from '@structured-growth/sg-ui/primitives';
export default function GridReferenceExample() {
type Course={id:string;name:string;status:string;score:number};
const rows:Course[]=[];
const columns:AppDataGridColumn<Course>[]=[{"field":"name","headerName":"Course","flex":1,"minWidth":180,"locked":true},{"field":"status","headerName":"Status","width":100}];
const [message,setMessage]=useState("No reference action yet");
return (
<>
<ThemeScope density="comfortable">
<Stack gap={3}>
<AppDataGrid label={"Empty dataset · comfortable"} rows={rows} columns={columns} getRowId={row=>row.id} getRowLabel={row=>row.name} defaultPaginationModel={{page:0,pageSize:6}} pageSizeOptions={[6,10]} loading={false} refreshing={false} errorMessage={undefined} onRetry={()=>setMessage('Retry requested')} onRowAction={row=>setMessage('Opened '+row.name)} style={{height:"max-content",flex:"none"}}/>
</Stack>
</ThemeScope>
</>
);
}
A fixed reference configuration with its own row interactions and host feedback.
Course | Status | |
|---|---|---|
Course 1 | archived | |
Course 2 | active | |
Course 3 | active | |
Course 4 | archived | |
Course 5 | active | |
Course 6 | active |
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import { AppDataGrid, AppDataGridShell, CourseCardFrame, type AppDataGridColumn } from '@structured-growth/sg-ui/components';
import { Stack, Typography, Link } from '@structured-growth/sg-ui/primitives';
export default function GridReferenceExample() {
type Course={id:string;name:string;status:string;score:number};
const rows:Course[]=[{"id":"1","name":"Course 1","status":"archived","score":100},{"id":"2","name":"Course 2","status":"active","score":97},{"id":"3","name":"Course 3","status":"active","score":94},{"id":"4","name":"Course 4","status":"archived","score":91},{"id":"5","name":"Course 5","status":"active","score":88},{"id":"6","name":"Course 6","status":"active","score":85}];
const columns:AppDataGridColumn<Course>[]=[{"field":"name","headerName":"Course","flex":1,"minWidth":180,"locked":true},{"field":"status","headerName":"Status","width":100}];
const [message,setMessage]=useState("No reference action yet");
return (
<>
<ThemeScope density="comfortable">
<Stack gap={3}>
<AppDataGrid label={"Error dataset · comfortable"} rows={rows} columns={columns} getRowId={row=>row.id} getRowLabel={row=>row.name} defaultPaginationModel={{page:0,pageSize:6}} pageSizeOptions={[6,10]} loading={false} refreshing={false} errorMessage={"Sample request failed."} onRetry={()=>setMessage('Retry requested')} onRowAction={row=>setMessage('Opened '+row.name)} style={{height:"max-content",flex:"none"}}/>
</Stack>
</ThemeScope>
</>
);
}