Interactive Resizable Column Table in React
This challenge asks you to build a React component that displays data in a table format with resizable columns. Users should be able to drag the column dividers to adjust the width of each column dynamically, creating a flexible and user-friendly data presentation. This is a common requirement in data dashboards and management applications where users need to customize their view.
Problem Description
You are tasked with creating a ResizableTable component in React using TypeScript. The component should accept an array of data objects as a prop, where each object represents a row in the table. The component should also accept an array of column headers as a prop, defining the columns to be displayed. Each column should be resizable by dragging its header divider.
What needs to be achieved:
- Display the data in a table format.
- Allow users to resize columns by dragging the dividers between column headers.
- Maintain the resized column widths across re-renders.
- Handle different data types gracefully (strings, numbers, etc.).
Key Requirements:
- Resizable Headers: Column headers should have a visual divider that users can drag to resize the column.
- Dynamic Widths: Column widths should change dynamically as the user drags the dividers.
- Persistent Widths: Resized column widths should be stored and applied on subsequent re-renders. Consider using
localStorageor a state management solution for persistence. - Responsive Design: While not strictly required, consider how the table will behave on smaller screens.
- Error Handling: Handle cases where the data doesn't match the column headers (e.g., missing data fields).
Expected Behavior:
- When the user drags a column divider, the width of that column should change smoothly.
- The table should reflow to accommodate the new column widths.
- Resized column widths should be saved and restored when the component re-renders.
- The table should display data correctly for various data types.
- If a data object is missing a field corresponding to a column header, display a reasonable placeholder (e.g., "N/A").
Edge Cases to Consider:
- Dragging a divider beyond the minimum or maximum allowed column width.
- Resizing columns when the table is very wide or very narrow.
- Handling empty data arrays.
- Handling cases where the number of columns in the data doesn't match the number of column headers.
- Performance with very large datasets (consider virtualization if necessary, though not required for this challenge).
Examples
Example 1:
Input: data = [{name: "Alice", age: 30, city: "New York"}, {name: "Bob", age: 25, city: "London"}]
columnHeaders = ["Name", "Age", "City"]
Output: A table with three columns: "Name", "Age", and "City". The user can drag the dividers between the headers to resize the columns.
Explanation: The table displays the data provided, and the user can interactively resize the columns.
Example 2:
Input: data = [{name: "Alice", age: 30}, {name: "Bob", age: 25}]
columnHeaders = ["Name", "Age", "City"]
Output: A table with three columns: "Name", "Age", and "City". The "City" column will display "N/A" for both rows.
Explanation: The data is missing the "City" field, so the component displays "N/A" as a placeholder.
Example 3: (Edge Case)
Input: data = []
columnHeaders = ["Name", "Age", "City"]
Output: An empty table with the specified column headers.
Explanation: The table is empty because there is no data to display.
Constraints
- Data Size: The data array should contain a maximum of 100 objects.
- Column Count: The number of column headers should match the number of fields in each data object (or provide a default value for missing fields).
- Performance: The resizing operation should be reasonably smooth (avoiding noticeable lag) even with the maximum data size. While virtualization isn't required, avoid inefficient re-renders.
- Column Widths: Initial column widths should be reasonable and prevent columns from being too narrow to display content. Minimum column width should be 100px. Maximum column width should be 500px.
Notes
- Consider using CSS for styling and layout.
- You can use any React libraries you are comfortable with (e.g., styled-components, Material-UI, etc.), but the core resizing logic should be implemented manually.
- Focus on the resizing functionality and the dynamic updating of column widths. Detailed styling is less important than correct behavior.
- Think about how to efficiently update the table when a column is resized. Avoid unnecessary re-renders.
- The persistence of column widths can be implemented using
localStorageor a state management library like Redux or Zustand. A simpleuseStatesolution is acceptable for this challenge.