{"id":30196272,"url":"https://github.com/soenneker/soenneker.quark.table","last_synced_at":"2025-08-13T05:17:39.371Z","repository":{"id":307723428,"uuid":"1029992002","full_name":"soenneker/soenneker.quark.table","owner":"soenneker","description":"A native Blazor table component.","archived":false,"fork":false,"pushed_at":"2025-08-07T15:27:21.000Z","size":207,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-10T17:47:01.510Z","etag":null,"topics":["blazor","blazorlibrary","csharp","data","dotnet","html","quark","quarktable","table","tables"],"latest_commit_sha":null,"homepage":"https://soenneker.com","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/soenneker.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"soenneker","buy_me_a_coffee":"soenneker","thanks_dev":"soenneker","ko_fi":"soenneker","patreon":"soenneker"}},"created_at":"2025-07-31T23:10:32.000Z","updated_at":"2025-08-07T15:26:36.000Z","dependencies_parsed_at":"2025-08-01T21:09:13.661Z","dependency_job_id":"1ff3e445-7f52-48c3-8c88-f479f6be8b69","html_url":"https://github.com/soenneker/soenneker.quark.table","commit_stats":null,"previous_names":["soenneker/soenneker.quark.table"],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/soenneker/soenneker.quark.table","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soenneker%2Fsoenneker.quark.table","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soenneker%2Fsoenneker.quark.table/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soenneker%2Fsoenneker.quark.table/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soenneker%2Fsoenneker.quark.table/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/soenneker","download_url":"https://codeload.github.com/soenneker/soenneker.quark.table/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soenneker%2Fsoenneker.quark.table/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270150038,"owners_count":24535877,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-12T02:00:09.011Z","response_time":80,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blazor","blazorlibrary","csharp","data","dotnet","html","quark","quarktable","table","tables"],"created_at":"2025-08-13T05:17:29.259Z","updated_at":"2025-08-13T05:17:39.327Z","avatar_url":"https://github.com/soenneker.png","language":"HTML","funding_links":["https://github.com/sponsors/soenneker","https://buymeacoffee.com/soenneker","https://thanks.dev/soenneker","https://ko-fi.com/soenneker","https://patreon.com/soenneker"],"categories":[],"sub_categories":[],"readme":"﻿[![](https://img.shields.io/nuget/v/soenneker.quark.table.svg?style=for-the-badge)](https://www.nuget.org/packages/soenneker.quark.table/)\n[![](https://img.shields.io/github/actions/workflow/status/soenneker/soenneker.quark.table/publish-package.yml?style=for-the-badge)](https://github.com/soenneker/soenneker.quark.table/actions/workflows/publish-package.yml)\n[![](https://img.shields.io/nuget/dt/soenneker.quark.table.svg?style=for-the-badge)](https://www.nuget.org/packages/soenneker.quark.table/)\n[![](https://img.shields.io/badge/Demo-Live-blueviolet?style=for-the-badge\u0026logo=github)](https://soenneker.github.io/soenneker.quark.table/)\n\n# Soenneker.Quark.Table\n\nA modern, component-driven Blazor table library that provides complete control over table structure and behavior through Razor components.\n\n## Features\n\n- **Component-Driven**: Every part of the table is a separate Razor component\n- **Full Control**: Users define table structure using Blazor markup\n- **Sortable Headers**: Individual column headers can be made sortable\n- **Search Integration**: Built-in search functionality with debouncing\n- **Pagination**: Server-side pagination with customizable controls\n- **Server-Side Processing**: Full support for server-side data processing\n- **Continuation Token Support**: Advanced pagination with continuation tokens\n- **Loading States**: Smooth loading behavior with overlay\n\n## Components\n\n### Core Components\n- **QuarkTable**: Main container component that manages state and events\n- **QuarkTableElement**: Table wrapper component\n- **QuarkThead**: Table header container\n- **QuarkTh**: Table header cell with optional sorting\n- **QuarkTbody**: Table body container\n- **QuarkTr**: Table row component\n- **QuarkTd**: Table data cell component\n\n### Feature Components\n- **QuarkTableSearch**: Standalone search component\n- **QuarkTablePagination**: Pagination controls component\n- **QuarkTableInfo**: Information display component (shows \"x-y of z\" format)\n- **QuarkTableBottomBar**: Bottom bar layout wrapper for info and pagination components\n- **QuarkTableTopBar**: Top bar layout component for header content\n- **QuarkTableLeft**: Left-aligned container component for use in topbar/bottombar\n- **QuarkTableRight**: Right-aligned container component for use in topbar/bottombar\n- **QuarkTableBarControls**: Container for buttons and custom controls\n- **QuarkTableNoData**: No data state component with customizable content\n- **QuarkTableLoader**: Loading state component\n- **QuarkTablePageSizeSelector**: Page size selector component\n\n### Legacy Components\n- **QuarkTableControls**: Legacy name for QuarkTableBottomBar (still supported)\n\n## Basic Usage\n\n```razor\n\u003cQuarkTable TotalRecords=\"100\" OnInteraction=\"OnInteraction\"\u003e\n    \u003cQuarkTableSearch Placeholder=\"Search employees...\" /\u003e\n    \n    \u003cQuarkTableElement\u003e\n        \u003cQuarkThead\u003e\n            \u003cQuarkTr\u003e\n                \u003cQuarkTh Sortable=\"true\" Searchable=\"true\"\u003eName\u003c/QuarkTh\u003e\n                \u003cQuarkTh Sortable=\"true\" Searchable=\"true\"\u003eEmail\u003c/QuarkTh\u003e\n                \u003cQuarkTh Sortable=\"false\" Searchable=\"true\"\u003eAge\u003c/QuarkTh\u003e\n            \u003c/QuarkTr\u003e\n        \u003c/QuarkThead\u003e\n        \n        \u003cQuarkTbody\u003e\n            @foreach (var person in people)\n            {\n                \u003cQuarkTr Key=\"@person.Id\"\u003e\n                    \u003cQuarkTd\u003e@person.Name\u003c/QuarkTd\u003e\n                    \u003cQuarkTd\u003e@person.Email\u003c/QuarkTd\u003e\n                    \u003cQuarkTd\u003e@person.Age\u003c/QuarkTd\u003e\n                \u003c/QuarkTr\u003e\n            }\n        \u003c/QuarkTbody\u003e\n    \u003c/QuarkTableElement\u003e\n    \n    \u003cQuarkTablePagination /\u003e\n\u003c/QuarkTable\u003e\n```\n\n## Custom Components\n\n### QuarkTableNoData\nDisplay a custom \"no data\" state when there are no records to show:\n\n```razor\n\u003cQuarkTableNoData\u003e\n    \u003cdiv style=\"text-align: center; padding: 2rem;\"\u003e\n        \u003ch4\u003eNo records found\u003c/h4\u003e\n        \u003cp\u003eTry adjusting your search criteria.\u003c/p\u003e\n    \u003c/div\u003e\n\u003c/QuarkTableNoData\u003e\n```\n\n### QuarkTableInfo\nDisplay table information independently of pagination:\n\n```razor\n\u003cQuarkTableInfo /\u003e\n\u003c!-- or with custom content --\u003e\n\u003cQuarkTableInfo\u003e\n    \u003cspan\u003eShowing @start-@end of @total records\u003c/span\u003e\n```\n\n### Bar Layout Positioning\n\nThe `QuarkTableBottomBar` and `QuarkTableTopBar` components support layout classes to control positioning when only one section is present:\n\n#### Bottom Bar - Right Only\nWhen only `QuarkTableRight` is specified in the bottom bar, use the `only-right` layout class to position it to the right:\n\n```razor\n\u003cQuarkTableBottomBar LayoutClass=\"only-right\"\u003e\n    \u003cQuarkTableRight\u003e\n        \u003cQuarkTableInfo /\u003e\n        \u003cQuarkTablePagination /\u003e\n    \u003c/QuarkTableRight\u003e\n\u003c/QuarkTableBottomBar\u003e\n```\n\n#### Top Bar - Left Only\nWhen only `QuarkTableLeft` is specified in the top bar, use the `only-left` layout class to anchor it to the right:\n\n```razor\n\u003cQuarkTableTopBar LayoutClass=\"only-left\"\u003e\n    \u003cQuarkTableLeft\u003e\n        \u003cQuarkTableSearch Placeholder=\"Search...\" /\u003e\n    \u003c/QuarkTableLeft\u003e\n\u003c/QuarkTableTopBar\u003e\n```\n\n#### Standard Layout\nWhen both left and right sections are present, no layout class is needed:\n\n```razor\n\u003cQuarkTableBottomBar\u003e\n    \u003cQuarkTableLeft\u003e\n        \u003cQuarkTableInfo /\u003e\n    \u003c/QuarkTableLeft\u003e\n    \u003cQuarkTableRight\u003e\n        \u003cQuarkTablePagination /\u003e\n    \u003c/QuarkTableRight\u003e\n\u003c/QuarkTableBottomBar\u003e\n```\n\u003c/QuarkTableInfo\u003e\n```\n\n### QuarkTableBottomBar\nLayout wrapper that combines info and pagination components with flexible layout options:\n\n```razor\n\u003c!-- Default layout: Info left, pagination right --\u003e\n\u003cQuarkTableBottomBar\u003e\n    \u003cQuarkTableLeft\u003e\n        \u003cQuarkTableInfo /\u003e\n    \u003c/QuarkTableLeft\u003e\n    \u003cQuarkTableRight\u003e\n        \u003cQuarkTablePagination /\u003e\n    \u003c/QuarkTableRight\u003e\n\u003c/QuarkTableBottomBar\u003e\n\n\u003c!-- Reversed layout: Info right, pagination left --\u003e\n\u003cQuarkTableBottomBar ControlsLayout=\"QuarkTableControlsLayout.InfoRightPaginationLeft\"\u003e\n    \u003cQuarkTableInfo /\u003e\n    \u003cQuarkTablePagination /\u003e\n\u003c/QuarkTableBottomBar\u003e\n\n\u003c!-- Using Left/Right components for custom layouts --\u003e\n\u003cQuarkTableBottomBar\u003e\n    \u003cQuarkTableLeft\u003e\n        \u003cQuarkTableInfo /\u003e\n        \u003cQuarkTablePageSizeSelector /\u003e\n    \u003c/QuarkTableLeft\u003e\n    \u003cQuarkTableRight\u003e\n        \u003cQuarkTablePagination /\u003e\n    \u003c/QuarkTableRight\u003e\n\u003c/QuarkTableBottomBar\u003e\n```\n\n## Server-Side Processing\n\n```csharp\nprivate async Task OnInteraction(DataTableServerSideRequest request)\n{\n    var query = dbContext.Employees.AsQueryable();\n\n    // Apply search\n    if (!string.IsNullOrEmpty(request.Search?.Value))\n    {\n        var searchTerm = request.Search.Value.ToLower();\n        query = query.Where(e =\u003e \n            e.Name.ToLower().Contains(searchTerm) ||\n            e.Email.ToLower().Contains(searchTerm));\n    }\n\n    // Apply sorting\n    if (request.Order?.Any() == true)\n    {\n        foreach (var order in request.Order)\n        {\n            query = order.Column switch\n            {\n                0 =\u003e order.Dir == \"asc\" ? query.OrderBy(e =\u003e e.Name) : query.OrderByDescending(e =\u003e e.Name),\n                1 =\u003e order.Dir == \"asc\" ? query.OrderBy(e =\u003e e.Email) : query.OrderByDescending(e =\u003e e.Email),\n                _ =\u003e query\n            };\n        }\n    }\n\n    var totalRecords = await query.CountAsync();\n    var pagedData = await query.Skip(request.Start).Take(request.Length).ToListAsync();\n\n    currentData = pagedData;\n    totalRecords = totalRecords;\n    StateHasChanged();\n}\n```\n\n## Continuation Token Support\n\n```csharp\nprivate async Task OnInteraction(DataTableServerSideRequest request)\n{\n    PagedResult\u003cEmployee\u003e pagedResult = await EmployeeService.GetEmployeesPaged(request);\n    _currentEmployees = pagedResult.Items;\n\n    if (_quarkTable != null)\n    {\n        _quarkTable.UpdateContinuationTokenPaging(\n            pagedResult.Items.Count,\n            pagedResult.ContinuationToken,\n            request.ContinuationToken);\n    }\n}\n```\n\n## Key Parameters\n\n### QuarkTable\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `TotalRecords` | `int` | `0` | Total number of records for pagination |\n| `Visible` | `bool` | `true` | Whether the table is visible |\n| `OnManualRequest` | `EventCallback\u003cDataTableServerSideRequest\u003e` | - | Server-side data processing callback |\n| `OnOrder` | `EventCallback\u003cQuarkTableOrderEventArgs\u003e` | - | Called when column sorting changes |\n| `Options` | `QuarkTableOptions` | `new()` | Table configuration options |\n\n### QuarkTh\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `Sortable` | `bool` | `true` | Enable sorting for this column |\n| `Searchable` | `bool` | `true` | Enable search for this column |\n\n### QuarkTableOptions\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `DefaultPageSize` | `int` | `10` | Default page size |\n| `SearchDebounceMs` | `int` | `300` | Search debounce delay in milliseconds |\n| `SearchPosition` | `SearchPosition` | `End` | Position of the search box |\n| `Debug` | `bool` | `false` | Enable debug logging |\n\n## Events\n\n- `OnInitialize`: Called when the table is initialized\n- `OnManualRequest`: Called when data needs to be loaded\n- `OnOrder`: Called when column sorting changes\n- `OnPageSizeChanged`: Called when page size changes\n- `OnGoToPage`: Called when navigating to a specific page","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoenneker%2Fsoenneker.quark.table","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsoenneker%2Fsoenneker.quark.table","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoenneker%2Fsoenneker.quark.table/lists"}