Reputation: 393
As the react-pdf library offering some limited component and no html tag is allowed to render in reactpdfrenderer.So i am in a trouble to make table using this library? Can any one please help me how can i create a table using this react-pdf library components?
Upvotes: 29
Views: 56405
Reputation: 14903
Thanks goes to Yash for the detailed answer given. This is what I ended up creating after seeing your example.
The main trick to create a "table" is to use fixed width columns on each row.
Note: Make the parent container width: '100%'
(table in this case) if you want to have your rows add up beyond 100% without overflowing/growing the parent. I would still recommend you try to have your total width add to 100% though, but the example below shows otherwise.
import { StyleSheet, Text, View } from '@react-pdf/renderer'
import PropTypes from 'prop-types'
const styles = StyleSheet.create({
table: {
width: '100%',
},
row: {
display: 'flex',
flexDirection: 'row',
borderTop: '1px solid #EEE',
paddingTop: 8,
paddingBottom: 8,
},
header: {
borderTop: 'none',
},
bold: {
fontWeight: 'bold',
},
// So Declarative and unDRY 👌
col1: {
width: '27%',
},
col2: {
width: '15%',
},
col3: {
width: '15%',
},
col4: {
width: '20%',
},
col5: {
width: '27%',
},
})
const ReportTable = ({ data, maximumDays }) => {
return (
<View style={styles.table}>
<View style={[styles.row, styles.bold, styles.header]}>
<Text style={styles.col1}>Name</Text>
<Text style={styles.col2}>Start Date</Text>
<Text style={styles.col3}>End Date</Text>
<Text style={styles.col4}>Days</Text>
<Text style={styles.col5}>Info</Text>
</View>
{data.map((row, i) => (
<View key={i} style={styles.row} wrap={false}>
<Text style={styles.col1}>
<Text style={styles.bold}>{row.lastName}</Text>, {row.firstName}
</Text>
<Text style={styles.col2}>{row.startDate}</Text>
<Text style={styles.col3}>{row.endDate}</Text>
<Text style={styles.col4}>
<Text style={styles.bold}>{row.days}</Text> of{' '}
{maximumDays}
</Text>
<Text style={styles.col5}>{row.info}</Text>
</View>
))}
</View>
)
}
ReportTable.propTypes = {
data: PropTypes.array.isRequired,
maximumDays: PropTypes.number.isRequired,
}
export default ReportTable
Upvotes: 9
Reputation: 41
simple table answer here: showcase
Code:
/* eslint-disable react-hooks/exhaustive-deps */
import React, { Fragment, useEffect, useState } from "react";
import { View, StyleSheet, Text } from "@react-pdf/renderer";
export default function Table({ data }) {
const [tableData, setTableData] = useState();
const styles = StyleSheet.create({
rowView: {
display: 'flex', flexDirection: 'row', borderTop: '1px solid #EEE', paddingTop: 8, paddingBottom: 8, textAlign: "center"
}
});
useEffect(() => {
if (data !== undefined) setTableData(data);
}, []);
return (
<>
{tableData &&
(
<Fragment>
<View style={styles.rowView}>
{tableData["column"].map((c) => <Text style={{
width: `${100 / tableData["column"].length}%`
}}>{c}</Text>)}
</View>
{tableData["data"].map((rowData) => <>
<View style={styles.rowView}>
{tableData["column"].map((c) =>
<Text style={{ width: `${100 / tableData["column"].length}%` }}>{rowData[c]}</Text>
)}
</View>
</>)}
</Fragment>
)}
</>
)
}
data format:
{
"column": [
"price",
"email",
"time"
],
"data": [
{
"price": "",
"email": "",
"time": ""
},
{
"price": "",
"email": "",
"time": ""
}
]
}
the table auto-populates based on the number of columns and auto sizes to take full page. just make sure to use column names as data keys
Upvotes: 4
Reputation: 147
function checkStrEmpty(str) {
return !(str && str.length > 1 && str.split(" ").join("").length > 0);
}
import { Text, View, StyleSheet } from "@react-pdf/renderer";
import React from "react";
function CustomTablePDF(props) {
const { fields = [], data = [] } = props;
let tableCol = {
borderStyle: BORDER_STYLE,
borderColor: BORDER_COLOR,
borderBottomColor: "#000",
borderWidth: 1,
borderLeftWidth: 0,
borderTopWidth: 0
};
return (
<View style={styles.table}>
<View style={[styles.tableRow, styles.headerBg]}>
{fields.map((_item, _idx) => (
<View
key={_idx}
style={[tableCol, { width: _item.width + "%" }]}
>
<Text
style={[
styles.tableCellHeader,
{ textAlign: "center" }
]}
>
{_item.title}
</Text>
</View>
))}
</View>
{data.map(
(item, idx) =>
item && (
<View key={idx} style={styles.tableRow}>
{fields.map((_item, _idx) => {
let val = item[_item.value] || "";
let value_alt =
(_item.value_alt &&
item[_item.value_alt]) ||
"";
if (_item.custom) {
return (
<View
key={_idx}
style={[
tableCol,
{ width: _item.width + "%" }
]}
>
<Text
style={[
styles.tableCell,
item.style ? item.style : {}
]}
>
{_item.component(item)}
</Text>
</View>
);
} else {
return (
<View
style={[
styles.tableCol,
{ width: _item.width + "%" }
]}
>
<Text
style={[
styles.tableCell,
item.style ? item.style : {}
]}
>
{checkStrEmpty(val)
? value_alt
: val || "-"}
</Text>
</View>
);
}
})}
</View>
)
)}
</View>
);
}
const BORDER_COLOR = "#000";
const BORDER_STYLE = "solid";
const styles = StyleSheet.create({
headerBg: {
backgroundColor: "#aaa"
},
table: {
display: "table",
width: "auto",
borderStyle: BORDER_STYLE,
borderColor: BORDER_COLOR,
borderWidth: 1
// borderRightWidth: 0,
// borderBottomWidth: 0,
},
tableRow: {
margin: "auto",
flexDirection: "row"
},
tableCellHeader: {
margin: 2,
fontSize: 13,
fontWeight: "bold"
// fontFamily: "CustomRoboto",
},
tableCell: {
margin: 2,
fontSize: 12
// fontFamily: "CustomRoboto",
},
textCenter: {
textAlign: "center"
}
});
export default CustomTablePDF;
use the component like this
const fields = [
{
title: " Agent Name",
custom: true,
component: (item) => `${item.agent_name}`,
width: "30"
},
{
title: " Policy No",
custom: true,
component: (item) => `${item.policy_no}`,
width: "35"
},
{
title: "Policy Class",
value: 'policy_class',
width: "20"
},
{
title: "Amount",
custom: true,
style: { textAlign: "right" },
className: "text-right",
component: (item) =>`${formatNumber(item.contribution)}`,
width: "15"
}
];
<CustomTablePDF fields={fields} data={details} />
Upvotes: 0
Reputation: 291
You can use as @David-Kucsai told in comment @david.kucsai/react-pdf-table
or without using
Data
const data = {
id: "5df3180a09ea16dc4b95f910",
items: [
{
sr: 1,
desc: "desc1",
xyz: 5,
},
{
sr: 2,
desc: "desc2",
xyz: 6,
},
],
};
app.js
import React, { Component, Fragment } from "react";
import { PDFViewer } from "@react-pdf/renderer";
import Table from "./components/reports/Table";
import data from "./data";
class App extends Component {
render() {
return (
<Fragment>
<PDFViewer width="1000" height="600">
<Table data={data} />
</PDFViewer>
</Fragment>
);
}
}
export default App;
Table.js
import React from "react";
import { Page, Document, StyleSheet } from "@react-pdf/renderer";
import ItemsTable from "./ItemsTable";
const styles = StyleSheet.create({
page: {
fontSize: 11,
flexDirection: "column",
},
});
const Table = ({ data }) => (
<Document>
<Page size="A4" style={styles.page}>
// ...
<ItemsTable data={data} />
// ...
</Page>
</Document>
);
export default Table;
ItemsTable.js
import React from "react";
import { View, StyleSheet } from "@react-pdf/renderer";
import TableRow from "./TableRow";
const styles = StyleSheet.create({
tableContainer: {
flexDirection: "row",
flexWrap: "wrap",
},
});
const ItemsTable = ({ data }) => (
<View style={styles.tableContainer}>
{/*<TableHeader />*/}
<TableRow items={data.items} />
{/*<TableFooter items={data.items} />*/}
</View>
);
export default ItemsTable;
TableRow.js
import React, { Fragment } from "react";
import { Text, View, StyleSheet } from "@react-pdf/renderer";
const styles = StyleSheet.create({
row: {
flexDirection: "row",
alignItems: "center",
},
description: {
width: "60%",
},
xyz: {
width: "40%",
},
});
const TableRow = ({ items }) => {
const rows = items.map((item) => (
<View style={styles.row} key={item.sr.toString()}>
<Text style={styles.description}>{item.desc}</Text>
<Text style={styles.xyz}>{item.xyz}</Text>
</View>
));
return <Fragment>{rows}</Fragment>;
};
export default TableRow;
For more information check Generate Dynamic PDF Invoices Using React and React-PDF
Upvotes: 19