React Resizable Columns Table
Build a React component that renders a table with columns that can be resized by the user. This is a common feature in data-heavy applications, allowing users to customize the layout to best view their information.
Problem Description
Your task is to create a functional React component named ResizableTable. This component should accept an array of data objects and an array of column definitions. Each column definition should specify the header text and a key to access the corresponding data property.
The table should render the provided data, with each column's width adjustable by the user. Resizing should occur by dragging a handle at the edge of each column header. The updated column widths should persist visually as the user drags.
Key Requirements:
- Render Table Data: Display data in a table format based on the provided
dataandcolumnsprops. - Resizable Columns: Implement functionality to resize columns by dragging the border between column headers.
- Visual Feedback: Provide visual cues during resizing (e.g., dragging a resize indicator).
- State Management: The component should internally manage the widths of each column.
- Column Definitions: The
columnsprop should be an array of objects, each with at leastheader(string) andkey(string) properties.
Expected Behavior:
- When the component mounts, columns should have a default width or a width derived from content.
- Users should be able to click and drag the right edge of any column header to resize that column.
- Resizing a column should affect its width and potentially the width of adjacent columns, or the overall table width. For this challenge, we'll focus on resizing a column and having it push the subsequent columns to the right. The leftmost column can shrink or expand freely.
- The content within the cells should adapt to the column width (e.g., text wrapping or ellipsis if it overflows). For simplicity in this challenge, assume content does not need advanced handling for overflow.
Edge Cases:
- No Data: How should the table behave if no data is provided?
- No Columns: How should the table behave if no columns are defined?
- Minimum Column Width: Consider a minimum width to prevent columns from becoming unusable.
- Maximum Table Width: While not strictly required for this initial challenge, consider how resizing might affect the overall table width.
Examples
Example 1: Basic Table Rendering
// Input Props
const columns = [
{ header: "Name", key: "name" },
{ header: "Age", key: "age" },
{ header: "City", key: "city" },
];
const data = [
{ name: "Alice", age: 30, city: "New York" },
{ name: "Bob", age: 25, city: "Los Angeles" },
{ name: "Charlie", age: 35, city: "Chicago" },
];
Output:
A table with three columns: "Name", "Age", and "City". Each row displays the corresponding data. Initially, columns might have equal width or widths determined by content.
Explanation: The component renders a standard table structure with headers and data rows.
Example 2: Resizing Interaction
Imagine the table from Example 1 is rendered.
Scenario: The user clicks and drags the right border of the "Name" column header to the right.
Expected Behavior:
- The "Name" column's width increases.
- The "Age" column moves further to the right, its width is not initially constrained by the "Name" column's expansion.
- The "City" column also moves further to the right.
Explanation: The drag interaction directly modifies the width of the targeted column, shifting subsequent elements.
Example 3: Minimum Column Width
Scenario: The user attempts to drag the right border of the "Age" column header to the left, past a predetermined minimum width (e.g., 50px).
Expected Behavior:
- The "Age" column stops resizing when it reaches the minimum width of 50px. It cannot be made smaller than this.
Explanation: A constraint is enforced to ensure columns remain visually usable.
Constraints
- The
dataprop will be an array of objects, where each object has string, number, or boolean values. - The
columnsprop will be an array of objects, each guaranteed to haveheader: stringandkey: string. - Initial column widths can be determined by content or a sensible default (e.g., 150px).
- Implement a minimum column width of
50px. - Focus on front-end state management within the React component. No need for server-side persistence or complex state management libraries.
Notes
- Consider using CSS for styling and layout. Flexbox or CSS Grid can be very helpful here.
- For handling the drag events, you'll likely need to track
mousedown,mousemove, andmouseupevents. - Think about how to translate mouse movement into pixel changes for column widths.
- You might want to use state (
useStateoruseReducer) to manage the widths of each column. - Consider separating the header and data cell rendering logic.
- For simplicity, assume that the parent container has enough width to accommodate resized columns. You don't need to implement horizontal scrolling for this challenge.