- π― Drag & Drop: Intuitive mapping creation with visual feedback
- π¨ Visual Connection Lines: Beautiful Bezier curves showing mapping relationships
- π Dark Mode: Automatic light/dark theme switching
- β‘ TypeScript: Full type safety and excellent developer experience
- ποΈ Customizable: Support for various field types such as
string,input,select
npm install react-table-mapping
# or
yarn add react-table-mapping
# or
pnpm add react-table-mapping"react": "^19.0.0",
"react-dom": "^19.0.0",
"@radix-ui/react-select": "^2.1.2",
"@radix-ui/react-slot": "^1.1.1"
"node": ">=22.0.0"
import 'react-table-mapping/styles';import React from 'react';
import { TableMapping } from 'react-table-mapping';
import type { FieldItemInput, TableMappingRef } from 'react-table-mapping';
function App() {
const tableMappingRef = React.useRef<TableMappingRef>(null);
// Define source table columns
const sourceColumns = [{ title: 'Name', key: 'name' }];
// Define target table columns
const targetColumns = [
{ title: 'Name', key: 'name' },
{ title: 'Data', key: 'data' },
{ title: 'Function', key: 'func' },
];
// Source field data
const sourceFields = [
{
name: {
type: 'input',
columnKey: 'name',
value: 'USER_ID',
attributes: {
//you can custom input attributes
style: {
height: '36px', //like this
},
},
onChange: (value) => console.log('Source name changed:', value),
},
id: 'source-0',
key: 'source-0',
},
] satisfies FieldItemInput[];
// Target field data
const targetFields = [
{
name: {
type: 'input',
columnKey: 'name',
value: 'KEY',
onChange: (value) => console.log('Target name changed:', value),
},
data: {
type: 'input',
columnKey: 'data',
value: '',
onChange: (value) => console.log('Target data changed:', value),
},
func: {
type: 'select',
columnKey: 'func',
defaultValue: 'NONE',
options: [
{ label: 'NONE', value: 'NONE' },
{ label: 'CONCAT', value: 'CONCAT' },
{ label: 'SUM', value: 'SUM' },
],
onChange: (value) => console.log('Target func changed:', value),
},
id: 'target-0',
key: 'target-0',
},
] satisfies FieldItemInput[];
// Initial mapping relationships
const initialMappings = [
{
id: 'mapping-source-0-target-0',
source: 'source-0',
target: 'target-0',
},
];
return (
<TableMapping
ref={tableMappingRef}
lineType="bezier"
sourceColumns={sourceColumns}
targetColumns={targetColumns}
sources={sourceFields}
targets={targetFields}
initialMappings={initialMappings}
onMappingChange={(mappings) => {
// you can get mappings, sources, targets, action
console.info('mappings', mappings);
}}
/>
);
}
export default App;| Prop | Type | Default | Description |
|---|---|---|---|
lineType |
'straight' | 'bezier' | 'step' |
'bezier' |
Type of connection lines |
sourceColumns |
HeaderColumnProps[] |
[] |
Source table header columns |
targetColumns |
HeaderColumnProps[] |
[] |
Target table header columns |
sources |
FieldItemInput[] |
[] |
Source field data |
targets |
FieldItemInput[] |
[] |
Target field data |
initialMappings |
Mapping[] |
[] |
Initial mapping relationships |
interface HeaderColumnProps {
title: string;
key: string;
}interface FieldItemInput {
id?: string;
key?: string;
[field: string]:
| {
type: 'string';
columnKey: string;
value: string;
}
| {
type: 'input';
columnKey: string;
value?: string;
defaultValue?: string;
attributes?: Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'>;
onChange?: (value: string) => void;
}
| {
type: 'select';
columnKey: string;
value?: string;
defaultValue?: string;
attributes?: Omit<React.SelectHTMLAttributes<HTMLSelectElement>, 'onChange'>;
options: {
label: string;
value: string;
disabled?: boolean;
}[];
onChange?: (value: string) => void;
}
| string;
}interface Mapping {
id: string;
source: string; // Source field ID
target: string; // Target field ID
}Display static text in table cells:
{
name: {
type: 'string',
columnKey: 'name',
value: 'Static Text'
}
}Editable text input with change handling:
{
name: {
type: 'input',
columnKey: 'name',
value: 'Initial Value',
onChange: (value) => console.log('New value:', value)
}
}Dropdown selection with options:
{
func: {
type: 'select',
columnKey: 'func',
defaultValue: 'CONCAT',
options: [
{ label: 'None', value: 'NONE' },
{ label: 'Concatenate', value: 'CONCAT' },
{ label: 'Sum', value: 'SUM' }
],
onChange: (value) => console.log('Selected:', value)
}
}The onMappingChange callback provides detailed information about state changes through action objects. Each action contains a type and payload with relevant data.
ADD_MAPPING
{
type: 'ADD_MAPPING',
payload: {
sourceId: string,
targetId: string,
mapping: Mapping
}
}REMOVE_MAPPING
{
type: 'REMOVE_MAPPING',
payload: {
mappingId: string,
removedMapping: Mapping | undefined
}
}CLEAR_MAPPINGS
{
type: 'CLEAR_MAPPINGS',
payload: {
clearedMappings: Mapping[]
}
}UPDATE_MAPPINGS
{
type: 'UPDATE_MAPPINGS',
payload: {
previousMappings: Mapping[],
newMappings: Mapping[]
}
}SAME_LINE_MAPPING
{
type: 'SAME_LINE_MAPPING',
payload: {
createdMappings: Mapping[]
}
}SAME_NAME_MAPPING
{
type: 'SAME_NAME_MAPPING',
payload: {
columnKey: string,
createdMappings: Mapping[]
}
}APPEND_SOURCE
{
type: 'APPEND_SOURCE',
payload: {
sourceField: FieldItem
}
}REMOVE_SOURCE
{
type: 'REMOVE_SOURCE',
payload: {
sourceId: string,
removedMappings: Mapping[]
}
}UPDATE_SOURCE_FIELDS
{
type: 'UPDATE_SOURCE_FIELDS',
payload: {
previousSources: FieldItem[],
newSources: FieldItem[]
}
}UPDATE_SOURCE_FIELD_VALUE
{
type: 'UPDATE_SOURCE_FIELD_VALUE',
payload: {
sourceId: string,
fieldKey: string,
previousValue: string,
newValue: string
}
}APPEND_TARGET
{
type: 'APPEND_TARGET',
payload: {
targetField: FieldItem
}
}REMOVE_TARGET
{
type: 'REMOVE_TARGET',
payload: {
targetId: string,
removedMappings: Mapping[]
}
}UPDATE_TARGET_FIELDS
{
type: 'UPDATE_TARGET_FIELDS',
payload: {
previousTargets: FieldItem[],
newTargets: FieldItem[]
}
}UPDATE_TARGET_FIELD_VALUE
{
type: 'UPDATE_TARGET_FIELD_VALUE',
payload: {
targetId: string,
fieldKey: string,
previousValue: string,
newValue: string
}
}The library uses CSS variables for theming and supports both light and dark modes automatically:
/* Custom theme variables */
:root {
--color-bg-mapping-primary: #ffffff;
--color-bg-mapping-secondary: #f3f4f9;
--color-text-default: #151826;
--color-border-default: #d3d6ea;
}
.dark {
--color-bg-mapping-primary: #242632;
--color-bg-mapping-secondary: #151826;
--color-text-default: #f3f4f9;
--color-border-default: #545667;
}const customFields = [
{
name: {
type: 'input',
columnKey: 'name',
value: 'Custom Field',
attributes: {
placeholder: 'Enter field name...',
maxLength: 50,
},
onChange: (value) => {
// Custom validation
if (value.length > 50) return;
console.log('Valid input:', value);
},
},
},
];# Clone the repository
$ git clone https://github.com/react-table-mapping/react-table-mapping.git
# Install dependencies
$ npm install
#or
$ yarn
# Start development server
$ npm run dev
# or
$ yarn dev
# Start storybook example
$ npm run storybook
# or
$ yarn storybookThis project is licensed under the MIT License - see the LICENSE file for details.
donghyun-git - [email protected]
Made with β€οΈ by donghyun-git