Using Shopify Polaris components with Gadget 

This page contains some code samples that can be used to integrate Shopify Polaris components with Gadget.

Polaris Data Table 

Use the following template to take data from a Gadget app and place it in a Polaris Data Table. Copy-pasting it into the frontend/ShopPage.jsx file that is generated when a new Gadget app is connected to Shopify will render a table containing the data from the shopifyShop model.

web/ShopPage.jsx
jsx
1import { useFindMany } from "@gadgetinc/react";
2import { AlphaCard, DataTable, Page, Pagination, Text, VerticalStack } from "@shopify/polaris";
3import { api } from "./api";
4import { useState, useCallback, useEffect } from "react";
5
6// helper functions used to capitalize headings
7function toCapitalizedWords(name) {
8 var words = name.match(/[A-Za-z][a-z]*/g) || [];
9 return words.map(capitalize).join(" ");
10}
11
12function capitalize(word) {
13 return word.charAt(0).toUpperCase() + word.substring(1);
14}
15
16const ShopPage = () => {
17 /**
18 * CHANGE NUM_RECORDS TO MODIFY THE NUMBER OF RECORDS FETCHED AT A SINGLE TIME
19 */
20 const NUM_RECORDS = 10;
21
22 // React state to manage table data and settings, as well as pagination cursor
23 const [cursor, setCursor] = useState({ first: NUM_RECORDS });
24 const [rows, setRows] = useState([]);
25 const [headings, setHeadings] = useState([]);
26 const [columnContentTypes, setColumnContentTypes] = useState([]);
27
28 /**
29 * CHANGE shopifyShop TO YOUR GADGET MODEL'S API IDENTIFIER TO FETCH DIFFERENT DATA
30 */
31 const [{ data, fetching, error }] = useFindMany(api.shopifyShop, {
32 ...cursor,
33 });
34
35 // set all data to state values
36 useEffect(() => {
37 if (data) {
38 // get JSON format for returned data
39 const jsonData = data.toJSON();
40
41 // loop through returned data to stringify objects
42 // this may not be necessary, depending on the shape of your displayed data model (see commented out line below)
43 // this can also be optimized if you know what columns need to be transformed (use column indexes instead of looping with Object.values(d))
44 setRows(
45 jsonData?.map((d) =>
46 Object.values(d).map((value) => {
47 // make sure objects are able to be rendered in table
48 if (value instanceof Object) {
49 /**
50 * YOU MAY NEED TO CHANGE THIS IF YOU NEED SPECIFIC TRANSFORMS FOR OBJECTS
51 */
52 return JSON.stringify(value);
53 }
54 return value;
55 })
56 )
57 );
58
59 // an alternative way to set rows if data transforms are not required
60 // setRows(jsonData.map(d => Object.values(d)))
61
62 // create readable headings and get column types
63 if (headings.length === 0 || headings.length !== Object.keys(jsonData[0]).length) {
64 const row = jsonData[0];
65 let headings = Object.keys(row);
66 setHeadings(headings.map((key) => toCapitalizedWords(key)));
67
68 let values = Object.values(row);
69 setColumnContentTypes(values.map((value) => (isNaN(value) ? "text" : "number")));
70 }
71 }
72 }, [data]);
73
74 // handle pagination
75 const pageForward = useCallback(() => {
76 setCursor({ after: data.endCursor, first: NUM_RECORDS });
77 }, [data]);
78 const pageBackward = useCallback(() => {
79 setCursor({ before: data.startCursor, last: NUM_RECORDS });
80 }, [data]);
81
82 // display any request errors
83 if (error) {
84 return (
85 <Page title="Error">
86 <Text variant="bodyMd" as="p">
87 Error: {error.toString()}
88 </Text>
89 </Page>
90 );
91 }
92
93 // draw the page and data table
94 return (
95 <Page title="Gadget + Polaris data table" fullWidth>
96 <AlphaCard>
97 <VerticalStack gap="5">
98 <Text>
99 For DataTable component details, see the{" "}
100 <a href="https://polaris.shopify.com/components/tables/data-table" target="_blank">
101 Polaris docs
102 </a>
103 .
104 </Text>
105 <Pagination
106 label="Use to paginate"
107 hasPrevious={data?.hasPreviousPage}
108 onPrevious={pageBackward}
109 hasNext={data?.hasNextPage}
110 onNext={pageForward}
111 />
112 {data && (
113 <DataTable columnContentTypes={columnContentTypes} headings={headings} rows={rows} hasZebraStripingOnData stickyHeader />
114 )}
115 </VerticalStack>
116 </AlphaCard>
117 </Page>
118 );
119};
120
121export default ShopPage;

There are a couple of things that can be changed to customize the table:

  • Displayed data model - change api.shopifyShop inside the useFindMany hook to the API identifier of the model displayed
  • Included columns - by default, all columns are displayed. This can be changed by adding a select condition to the useFindMany hook
web/ShopPage.jsx
jsx
1// for example: only include the shop id and name in the table
2const [{ data, fetching, error }] = useFindMany(api.shopifyShop, {
3 ...cursor,
4 select: {
5 id: true,
6 name: true,
7 },
8});
  • NUM_RECORDS - the number of records to fetch and display at a time. Pagination is built-in, and this is the way to set the page size