I'm trying to create a simple table layout using flexbox (so the table is properly responsive). I'm doing it like this (you need react and bootstrap):
export function UITest(){
const data = [
{
Name: "John Doe",
Address: "123 Main St, Springfield, IL",
Insurance: "Health Insurance Co.",
Phone: "(555) 123-4567",
Email: "john.doe@example.com"
},
{
Name: "Jane Smith",
Address: "456 Oak Rd, Shelbyville, IL",
Insurance: "Life Care Insurance",
Phone: "(555) 234-5678",
Email: "jane.smith@example.com"
},
{
Name: "Lǐ Tiānyǔ Zé Fēng Chéng Zhì Hóng Wěi",
Address: "789 Pine Ln, Capital City, IL",
Insurance: "Auto Protection Insurance",
Phone: "(555) 345-6789",
Email: "li.the.god@example.com"
},
{
Name: "Emily White",
Address: "101 Maple Ave, Ogden, IL",
Insurance: "Health First Insurance",
Phone: "(555) 456-7890",
Email: "emily.white@example.com"
}
];
const titles=["Name", "Address", "Insurance", "Phone", "Email"]
return(
<div className="container bg-secondary my-3 p-3">
<h1 className="mb-5">UiTest</h1>
<div className="d-flex flex-column justify-content-center overflow-scroll">
<div className="border-bottom border-2 d-flex flex-row justify-content-center">
{titles.map((title, index) => (
<div key={index} className={"border-start p-2"+(title==="Insurance"?" flex-grow-1":"")}>{title}</div>
))}
</div>
{data.map((item, index) => (
<div key={index} className="d-flex justify-content-center bg-info m-2 p-2 rounded">
{Object.entries(item).map(([key, value], index) => (
<div key={index} className={"border border-1 p-2"+(key==="Insurance"?" flex-grow-1":"")}>{value}</div>
))}
</div>
))}
</div>
</div>
)
}
The problem is, the columns don't line up properly (borders are to visualize the problem):
I've tried solving this with a table but it will not work, because whatever makes the table line up the colums correctly does not play nice with flexbox. Also you cannot style rows like I want to with tables. How can I make the columns line up properly (ideally without setting a fixed width and while still retaining the responsiveness of the table, where it flexes along the insurance column)
Unfortunately flex layout doesn't have the context of the size of the previous element. It would be recommended to use <table>
to populate your data properly.
However, you want to keep your nested structure but don't want to deal with <table>
, an alternate way is using subgrid
.
Here's the JSX code you could use to assign the proper style
without actually creating CSS.
<div className="container bg-secondary my-3 p-3">
<h1 className="mb-5">UiTest</h1>
<div
className="justify-content-center overflow-scroll"
style={{ display: 'grid', gridTemplateColumns: titles.map(title => title === 'Insurance' ? '1fr' : 'auto').join(' '), gridAutoFlow: 'row' }}
>
<div
className="border-bottom border-2"
style={{ display: 'grid', gridColumn: '1 / -1', gridTemplateColumns: 'subgrid' }}
>
{titles.map((title, index) => (
<div key={index} className="border-start p-2">{title}</div>
))}
</div>
{data.map((item, index) => (
<div
key={index}
className="bg-info m-2 p-2 rounded"
style={{ display: 'grid', gridColumn: '1 / -1', gridTemplateColumns: 'subgrid' }}
>
{Object.entries(item).map(([key, value], index) => (
<div key={index} className="border-start p-2">{value}</div>
))}
</div>
))}
</div>
</div>
This is the HTML code it gererates:
<div class="container bg-secondary my-3 p-3">
<h1 class="mb-5">UiTest</h1>
<div style="display: grid; grid-template-columns: auto auto 1fr auto auto; grid-auto-flow: row;" class="overflow-scroll">
<div style="display: grid; grid-column: 1 / -1; grid-template-columns: subgrid;" class="border-bottom border-2 d-flex flex-row justify-content-center">
<div class="border-start p-2">Name</div>
<div class="border-start p-2">Address</div>
<div class="border-start p-2">Insurance</div>
<div class="border-start p-2">Phone</div>
<div class="border-start p-2">Email</div>
</div>
<div style="display: grid; grid-column: 1 / -1; grid-template-columns: subgrid;" class="g-info m-2 p-2 rounded">
<div class="border border-1 p-2">John Doe</div>
<div class="border border-1 p-2">123 Main St, Springfield, IL</div>
<div class="border border-1 p-2">Health Insurance Co.</div>
<div class="border border-1 p-2">(555) 123-4567</div>
<div class="border border-1 p-2">john.doe@example.com</div>
</div>
<div style="display: grid; grid-column: 1 / -1; grid-template-columns: subgrid;" class="g-info m-2 p-2 rounded">
<div class="border border-1 p-2">Jane Smith</div>
<div class="border border-1 p-2">456 Oak Rd, Shelbyville, IL</div>
<div class="border border-1 p-2">Life Care Insurance</div>
<div class="border border-1 p-2">(555) 234-5678</div>
<div class="border border-1 p-2">jane.smith@example.com</div>
</div>
<div style="display: grid; grid-column: 1 / -1; grid-template-columns: subgrid;" class="g-info m-2 p-2 rounded">
<div class="border border-1 p-2">Lǐ Tiānyǔ Zé Fēng Chéng Zhì Hóng Wěi</div>
<div class="border border-1 p-2">789 Pine Ln, Capital City, IL</div>
<div class="border border-1 p-2">Auto Protection Insurance</div>
<div class="border border-1 p-2">(555) 345-6789</div>
<div class="border border-1 p-2">li.the.god@example.com</div>
</div>
<div style="display: grid; grid-column: 1 / -1; grid-template-columns: subgrid;" class="g-info m-2 p-2 rounded">
<div class="border border-1 p-2">Emily White</div>
<div class="border border-1 p-2">101 Maple Ave, Ogden, IL</div>
<div class="border border-1 p-2">Health First Insurance</div>
<div class="border border-1 p-2">(555) 456-7890</div>
<div class="border border-1 p-2">emily.white@example.com</div>
</div>
</div>
</div>
See the live demo