A quick start project that demonstrates how to bind remote data from a HotChocolate-powered ASP.NET Core GraphQL service to the Syncfusion React Pivot Table using the GraphQLAdaptor. The sample includes both data retrieval and CRUD operations through GraphQL queries and mutations.
- 🚀 Quick Overview
- ✨ Key Features
- 🛠️ Prerequisites
- 📂 Project Structure
- 🏗️ Architecture and Data Flow
- ⚙️ Backend Implementation
- ⚛️ Frontend Integration
▶️ Running the Sample- 🔧 Troubleshooting
- 📚 Additional Resources
This sample connects the Syncfusion React Pivot Table to an ASP.NET Core backend that exposes a GraphQL endpoint with HotChocolate. The frontend uses the Syncfusion DataManager together with the GraphQLAdaptor, while the backend exposes a query resolver for reading data and mutation resolvers for insert, update, and delete operations.
| Component | Technology | Purpose |
|---|---|---|
| Frontend | React + Vite + Syncfusion Pivot Table | Render the Pivot Table UI and bind remote data |
| Backend | ASP.NET Core + HotChocolate | Expose GraphQL queries and mutations |
| Data layer | In-memory sample data | Provide a runnable sample without a database |
| Adaptor | GraphQLAdaptor | Translate Pivot Table operations into GraphQL requests |
💡 The sample uses an in-memory dataset, so changes made through the Pivot Table editing experience are available only for the current process and will be reset when the backend restarts.
- 📊 Remote data binding from a GraphQL endpoint to the Syncfusion Pivot Table
- 🔄 CRUD support through GraphQL mutations for add, edit, and delete actions
- 🧩 GraphQL response mapping for the Pivot Table’s expected
resultandcountstructure - 🧠 Custom GraphQL resolver logic for returning and modifying sample order data
- 🧱 HotChocolate server setup with CORS enabled for local development
- 🧾 GraphQL field naming configured with
GraphQLNameattributes for the sample data model
Make sure the following software is available before running the sample.
| Software / Package | Version | Purpose |
|---|---|---|
| .NET SDK | 10.0 or later | Build and run the ASP.NET Core backend |
| Node.js | 20.x or later | Run the React client |
| npm | Latest | Install frontend dependencies |
| Visual Studio / VS Code | Latest | Edit and run the sample |
| Syncfusion EJ2 packages | Current project dependencies | Render the Pivot Table and use the GraphQLAdaptor |
The backend project targets .NET 10 in GraphQLAdaptor/GraphQLAdaptor.csproj, and the frontend uses Vite with React in Client/package.json.
react-pivot-table-graphql-hotchocolate/
├── Client/ # React + Vite frontend
│ ├── src/App.tsx # Pivot Table configuration and GraphQLAdaptor setup
│ └── package.json # Frontend dependencies and scripts
├── GraphQLAdaptor/ # ASP.NET Core HotChocolate backend
│ ├── GraphQL/
│ │ ├── Mutation.cs # GraphQL mutation resolvers
│ │ ├── OrdersReturnType.cs # Response wrapper with result/count
│ │ └── Query.cs # GraphQL query resolver
│ ├── Models/OrdersDetails.cs # Sample order model and in-memory data
│ ├── Program.cs # GraphQL server and CORS configuration
│ └── Properties/launchSettings.json
└── README.md # This file
The sample follows a simple request flow:
- The Syncfusion Pivot Table is rendered in the React client.
- The Pivot Table uses DataManager with the GraphQLAdaptor to send a GraphQL request to the backend.
- HotChocolate receives the request, executes the configured query resolver, and returns the dataset.
- The GraphQLAdaptor maps the response to the Pivot Table’s expected structure using
resultandcount. - When editing is performed, the adaptor sends GraphQL mutations for insert, update, or delete operations.
- Read operation:
GraphQLAdaptorsends a GraphQLquerydocument to/graphql. - Write operations:
GraphQLAdaptorsends GraphQLmutationdocuments for insert, update, and remove. - Backend response: the sample returns an object containing both the data rows and the total count.
The client-side configuration in Client/src/App.tsx uses the GraphQLAdaptor with the following mapping:
response: {
result: 'orders.result',
count: 'orders.count'
}This tells the adaptor to read the result rows from the orders.result property and the total record count from orders.count in the GraphQL response.
The backend lives in GraphQLAdaptor and is configured as a HotChocolate GraphQL server.
The GraphQL server is registered in GraphQLAdaptor/Program.cs. The service is configured to:
- expose a GraphQL endpoint at
/graphql - register the query resolver from
Query - register the mutation resolver from
Mutation - enable projection support through
AddProjections() - enable CORS for local development
builder.Services
.AddGraphQLServer()
.AddQueryType<Query>()
.AddMutationType<Mutation>()
.AddProjections();The sample data model is defined in GraphQLAdaptor/Models/OrdersDetails.cs. It contains a simple in-memory list of sample orders and exposes the following fields:
OrderIDCustomerIDEmployeeIDFreight
The model uses GraphQLName attributes so the GraphQL field names match the sample data structure.
The query resolver in GraphQLAdaptor/GraphQL/Query.cs returns a wrapper object with both the data rows and the total count:
public OrdersReturnType GetOrders()
{
var allOrders = OrdersDetails.GetAllRecords();
var query = allOrders.AsQueryable();
var totalCount = query.Count();
return new OrdersReturnType
{
Result = query.ToList(),
Count = totalCount
};
}The response shape is defined by GraphQLAdaptor/GraphQL/OrdersReturnType.cs, which exposes:
Result: the list of records returned to the Pivot TableCount: the total number of records available
The mutation layer in GraphQLAdaptor/GraphQL/Mutation.cs implements the CRUD operations used by the Pivot Table editing experience.
AddOrder: inserts a new record into the in-memory listUpdateOrder: updates an existing order based onOrderIDDeleteOrder: removes an existing order byOrderID
The mutations receive an input type named OrdersDetailsInput, which contains a subset of the model fields used by this sample:
public class OrdersDetailsInput
{
[GraphQLName("OrderID")]
public int? OrderID { get; set; }
[GraphQLName("CustomerID")]
public string? CustomerID { get; set; }
[GraphQLName("EmployeeID")]
public int? EmployeeID { get; set; }
[GraphQLName("Freight")]
public double? Freight { get; set; }
}The current implementation intentionally keeps the data in memory and does not rely on a database. It also includes simple business behavior:
- new records are inserted at the beginning of the list
- updates change only the fields that are provided in the mutation payload
- delete operations remove the matching record by
OrderID
This makes the sample easy to run and understand while still demonstrating the full query/mutation lifecycle.
The client is implemented in Client/src/App.tsx and configures the Pivot Table to use the GraphQLAdaptor.
The React app creates a DataManager that points to the local GraphQL endpoint:
const data = new DataManager({
url: 'http://localhost:5190/graphql/',
adaptor: new GraphQLAdaptor({
response: {
result: 'orders.result',
count: 'orders.count'
},
query: `query GetOrders() {
orders() {
result {
OrderID
CustomerID
EmployeeID
Freight
}
count
}
}`,
getMutation: function (action) {
if (action === 'insert') {
return `mutation CreateOrder($value: OrdersDetailsInput!) {
addOrder(input: $value) {
OrderID
CustomerID
EmployeeID
Freight
}
}`;
}
if (action === 'update') {
return `mutation UpdateOrder($key: Int!, $keyColumn: String, $value: OrdersDetailsInput!) {
updateOrder(key: $key, keyColumn: $keyColumn, input: $value) {
OrderID
CustomerID
EmployeeID
Freight
}
}`;
}
if (action === 'remove') {
return `mutation DeleteOrder($key: Int!) {
deleteOrder(orderID: $key)
}`;
}
return '';
}
}),
crossDomain: true
});The Pivot Table is configured with rows, columns, and values for the sample data:
- rows:
OrderID - columns:
CustomerID - values:
Freight
Editing is enabled through the editSettings configuration so users can add, update, and delete records from the Pivot Table drill-through experience.
The beginDrillThrough handler in Client/src/App.tsx marks the OrderID column as the primary key so the Syncfusion DataManager can use it for update and delete operations.
You need two terminals: one for the backend and one for the frontend.
cd GraphQLAdaptor
dotnet restore
dotnet runThe backend will be available at a local URL such as http://localhost:5190 or https://localhost:7163 based on the launch profile in GraphQLAdaptor/Properties/launchSettings.json.
Open the browser and navigate to:
http://localhost:5190/graphql/
You can test the endpoint with a query such as:
query {
orders {
result {
OrderID
CustomerID
EmployeeID
Freight
}
count
}
}Open a second terminal and run:
cd Client
npm install
npm run devThe Vite development server will start, and the app will typically open at http://localhost:5173/.
Once both applications are running:
- the Pivot Table should load data from the GraphQL backend
- the browser network tab should show GraphQL requests to
/graphql - editing actions should trigger the corresponding GraphQL mutations
| Issue | Possible cause | Resolution |
|---|---|---|
| Empty Pivot Table | The query result or response mapping is incorrect | Confirm that the GraphQL query returns result and count in the expected shape and that the adaptor mapping points to orders.result and orders.count |
| CORS errors | The browser blocks requests from the frontend origin | Ensure CORS is enabled in GraphQLAdaptor/Program.cs and that the backend is running |
| GraphQL endpoint not reachable | The backend is not started or the URL is incorrect | Verify the backend URL in Client/src/App.tsx and check the launch profile port |
| CRUD operations fail | The mutation names or input shape do not match the server | Confirm that the client uses addOrder, updateOrder, and deleteOrder exactly as implemented in GraphQLAdaptor/GraphQL/Mutation.cs |
| Data changes are not preserved | The sample uses in-memory data | Restarting the backend will reset the sample data, because the implementation does not use a persistent database |
- Syncfusion React Pivot Table documentation
- HotChocolate documentation
- GraphQL documentation
- Syncfusion GraphQLAdaptor documentation
If you want to extend this sample further, the next natural step is to replace the in-memory list with a real data source such as Entity Framework Core, SQL Server, or another persistence layer while keeping the same GraphQL and adaptor configuration.
Contributions are welcome and appreciated! 💖
- 🍴 Fork the repository.
- 🌿 Create a feature branch:
git checkout -b feature/my-awesome-change - 💾 Commit your changes:
git commit -m "Add my awesome change" - 📤 Push to your branch:
git push origin feature/my-awesome-change - 🔁 Open a Pull Request describing the change and its motivation.
- Follow the existing code style in both the React and ASP.NET Core projects.
- Keep changes focused — one feature or fix per pull request.
- Update or add documentation (
README.md,webapi-adaptor.md) when behavior changes. - Test your changes locally against both the backend and frontend before submitting.
This project is released under the MIT License. You are free to use, modify, and distribute the code in personal and commercial projects. See the LICENSE file for full text.
- 📘 Documentation: Syncfusion® React Pivot Table Docs
- 💬 Community forum: Syncfusion® Community
- 🐛 Bug reports & feature requests: GitHub Issues
- 📧 Direct support: Syncfusion® Support Portal (for licensed users)
- 📖 Web API Adaptor Guide: WebApiAdaptor Documentation
⭐ If this project helped you, please consider giving it a star on GitHub — it helps others discover it!