diff --git a/client/packages/lowcoder/src/components/table/EditableCell.tsx b/client/packages/lowcoder/src/components/table/EditableCell.tsx
index 3e68cfdff8..f8f9ebe16d 100644
--- a/client/packages/lowcoder/src/components/table/EditableCell.tsx
+++ b/client/packages/lowcoder/src/components/table/EditableCell.tsx
@@ -37,6 +37,7 @@ export interface CellProps {
   candidateStatus?: { text: string; status: StatusType }[];
   textOverflow?: boolean;
   cellTooltip?: string;
+  editMode?: string;
   onTableEvent?: (eventName: any) => void;
 }
 
@@ -94,6 +95,7 @@ export function EditableCell<T extends JSONValue>(props: EditableCellProps<T>) {
     candidateTags,
     // tagColors
     candidateStatus,
+    editMode,
     onTableEvent,
   } = props;
   const status = _.isNil(changeValue) ? "normal" : "toSave";
@@ -101,10 +103,11 @@ export function EditableCell<T extends JSONValue>(props: EditableCellProps<T>) {
   const { isEditing, setIsEditing } = useContext(TableCellContext);
   const value = changeValue ?? baseValue!;
   const [tmpValue, setTmpValue] = useState<T | null>(value);
+  const singleClickEdit = editMode === 'single'; 
 
   useEffect(() => {
     setTmpValue(value);
-  }, [value]);
+  }, [JSON.stringify(value)]);
 
   const onChange = useCallback(
     (value: T) => {
@@ -125,11 +128,13 @@ export function EditableCell<T extends JSONValue>(props: EditableCellProps<T>) {
     if(!_.isEqual(tmpValue, value)) {
       onTableEvent?.('columnEdited');
     }
-  }, [dispatch, baseValue, tmpValue]);
+  }, [dispatch, JSON.stringify(baseValue), JSON.stringify(tmpValue)]);
+
   const editView = useMemo(
     () => editViewFn?.({ value, onChange, onChangeEnd }) ?? <></>,
-    [editViewFn, value, onChange, onChangeEnd]
+    [editViewFn, JSON.stringify(value), onChange, onChangeEnd]
   );
+
   const enterEditFn = useCallback(() => {
     if (editable) setIsEditing(true);
   }, [editable]);
@@ -137,9 +142,13 @@ export function EditableCell<T extends JSONValue>(props: EditableCellProps<T>) {
   if (isEditing) {
     return (
       <>
-        <BorderDiv />
+        <BorderDiv className="editing-border" />
         <TagsContext.Provider value={candidateTags ?? []}>
-          <StatusContext.Provider value={candidateStatus ?? []}>{editView}</StatusContext.Provider>
+          <StatusContext.Provider value={candidateStatus ?? []}>
+            <div className="editing-wrapper">
+              {editView}
+            </div>
+          </StatusContext.Provider>
         </TagsContext.Provider>
       </>
     );
@@ -151,7 +160,12 @@ export function EditableCell<T extends JSONValue>(props: EditableCellProps<T>) {
       >
         {status === "toSave" && !isEditing && <EditableChip />}
         <CellWrapper tooltipTitle={props.cellTooltip}>
-          {normalView}
+          <div
+            tabIndex={editable ? 0 : -1 }
+            onFocus={enterEditFn}
+          >
+            {normalView}
+          </div>
         </CellWrapper>
         {/* overlay on normal view to handle double click for editing */}
         {editable && (
@@ -164,7 +178,8 @@ export function EditableCell<T extends JSONValue>(props: EditableCellProps<T>) {
                 width: '100%',
                 height: '100%',
               }}
-              onDoubleClick={enterEditFn}
+              onDoubleClick={!singleClickEdit ? enterEditFn : undefined}
+              onClick={singleClickEdit ? enterEditFn : undefined}
             >
             </div>
           </CellWrapper>
diff --git a/client/packages/lowcoder/src/comps/comps/selectInputComp/selectCompConstants.tsx b/client/packages/lowcoder/src/comps/comps/selectInputComp/selectCompConstants.tsx
index 41851324fe..360a684600 100644
--- a/client/packages/lowcoder/src/comps/comps/selectInputComp/selectCompConstants.tsx
+++ b/client/packages/lowcoder/src/comps/comps/selectInputComp/selectCompConstants.tsx
@@ -253,10 +253,12 @@ export const SelectUIView = (
     inputFieldStyle: SelectStyleType;
     onChange: (value: any) => void;
     dispatch: DispatchType;
+    autoFocus?: boolean;
   }
 ) => {
   return <Select
     ref={props.viewRef}
+    autoFocus={props.autoFocus}
     mode={props.mode}
     $inputFieldStyle={props.inputFieldStyle}
     $style={props.style as SelectStyleType & MultiSelectStyleType}
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/ColumnNumberComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/ColumnNumberComp.tsx
index 871d7fbf92..8c7ea937d3 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/ColumnNumberComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/ColumnNumberComp.tsx
@@ -14,7 +14,7 @@ const InputNumberWrapper = styled.div`
     width: 100%;
     border-radius: 0;
     background: transparent !important;
-    padding: 0 !important;
+    // padding: 0 !important;
     box-shadow: none;
 
     input {
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDateComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDateComp.tsx
index 471f4f5461..d077f6d799 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDateComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDateComp.tsx
@@ -49,9 +49,9 @@ const DatePickerStyled = styled(DatePicker)<{ $open: boolean }>`
     top: 0.5px;
     display: flex;
     align-items: center;
-    background: #fff;
+    // background: #fff;
     padding: 0 3px;
-    border-left: 1px solid #d7d9e0;
+    // border-left: 1px solid #d7d9e0;
   }
 `;
 
@@ -183,7 +183,7 @@ export const DateEdit = (props: DateEditProps) => {
         nextIcon={<IconNext />}
         superNextIcon={<IconSuperNext />}
         superPrevIcon={<SuperPrevIcon />}
-        allowClear={false}
+        allowClear={true}
         variant="borderless"
         autoFocus
         value={tempValue}
@@ -197,7 +197,9 @@ export const DateEdit = (props: DateEditProps) => {
           overflow: "hidden",
         }}
         onOpenChange={(open) => setPanelOpen(open)}
-        onChange={(value, dateString) => props.onChange(dateString as string)}
+        onChange={(value, dateString) => {
+          props.onChange(dateString as string)
+        }}
         onBlur={() => props.onChangeEnd()}
       />
     </Wrapper>
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnSelectComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnSelectComp.tsx
index 8cd83d4e92..a51b182e10 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnSelectComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnSelectComp.tsx
@@ -7,6 +7,73 @@ import { StringControl } from "comps/controls/codeControl";
 import { trans } from "i18n";
 import { ColumnTypeCompBuilder, ColumnTypeViewFn } from "../columnTypeCompBuilder";
 import { ColumnValueTooltip } from "../simpleColumnTypeComps";
+import { styled } from "styled-components";
+
+const Wrapper = styled.div`
+  display: inline-flex;
+  align-items: center;
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  top: 0;
+  background: transparent !important;
+  padding: 8px;
+
+  > div {
+    width: 100%;
+    height: 100%;
+  }
+
+  .ant-select {
+    height: 100%;
+    .ant-select-selector {
+      padding: 0 7px;
+      height: 100%;
+      overflow: hidden;
+      .ant-select-selection-item {
+        display: inline-flex;
+        align-items: center;
+        padding-right: 24px;
+      }
+    }
+    .ant-select-arrow {
+      height: calc(100% - 3px);
+      width: fit-content;
+      top: 1.5px;
+      margin-top: 0;
+      background-color: white;
+      right: 1.5px;
+      border-right: 1px solid #d7d9e0;
+      cursor: pointer;
+      pointer-events: auto;
+      svg {
+        min-width: 18px;
+        min-height: 18px;
+      }
+      &:hover svg path {
+        fill: #315efb;
+      }
+    }
+    .ant-select-selector .ant-select-selection-search {
+      left: 7px;
+      input {
+        height: 100%;
+      }
+    }
+    &.ant-select-open {
+      .ant-select-arrow {
+        border-right: none;
+        border-left: 1px solid #d7d9e0;
+        svg g path {
+          fill: #315efb;
+        }
+      }
+      .ant-select-selection-item {
+        opacity: 0.4;
+      }
+    }
+  }
+`;
 
 const childrenMap = {
   text: StringControl,
@@ -28,6 +95,8 @@ const SelectEdit = (props: SelectEditProps) => {
   const [currentValue, setCurrentValue] = useState(props.initialValue);
   return (
     <SelectUIView
+      autoFocus
+      allowClear
       {...defaultProps}
       value={currentValue}
       options={props.options}
@@ -67,12 +136,14 @@ export const ColumnSelectComp = (function () {
   )
     .setEditViewFn((props) => {
       return (
-        <SelectEdit
-          initialValue={props.value}
-          options={options}
-          onChange={props.onChange}
-          onChangeEnd={props.onChangeEnd}
-        />
+        <Wrapper>
+          <SelectEdit
+            initialValue={props.value}
+            options={options}
+            onChange={props.onChange}
+            onChangeEnd={props.onChangeEnd}
+          />
+        </Wrapper>
       )
     })
     .setPropertyViewFn((children) => {
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnStatusComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnStatusComp.tsx
index 5579a4cc6c..b8181f91a7 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnStatusComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnStatusComp.tsx
@@ -48,7 +48,7 @@ const StatusEdit = (props: StatusEditPropsType) => {
   const defaultStatus = useContext(StatusContext);
   const [status, setStatus] = useState(defaultStatus);
   const [allOptions, setAllOptions] = useState(BadgeStatusOptions);
-  const [open, setOpen] = useState(true);
+  const [open, setOpen] = useState(false);
 
   return (
     <Wrapper>
@@ -84,6 +84,7 @@ const StatusEdit = (props: StatusEditPropsType) => {
             value,
             status: status.find((item) => item.text === value)?.status || "none",
           });
+          setOpen(false)
         }}
         dropdownRender={(originNode: ReactNode) => (
           <DropdownStyled>
@@ -91,11 +92,12 @@ const StatusEdit = (props: StatusEditPropsType) => {
           </DropdownStyled>
         )}
         dropdownStyle={{ marginTop: "7px", padding: "8px 0 6px 0" }}
-        onBlur={props.onChangeEnd}
-        onKeyDown={(e) => {
-          if (e.key === "Enter") {
-            props.onChangeEnd();
-          }
+        onBlur={() => {
+          props.onChangeEnd();
+          setOpen(false);
+        }}
+        onFocus={() => {
+          setOpen(true);
         }}
         onClick={() => setOpen(!open)}
       >
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTagsComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTagsComp.tsx
index 97278acf87..61ed6cb531 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTagsComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTagsComp.tsx
@@ -92,6 +92,8 @@ export const Wrapper = styled.div`
   position: absolute;
   top: 0;
   background: transparent !important;
+  padding: 8px;
+
   > div {
     width: 100%;
     height: 100%;
@@ -147,7 +149,7 @@ export const Wrapper = styled.div`
     }
   }
   .ant-tag {
-    margin-left: 20px;
+    margin-left: 5px;
   }
   .ant-tag svg {
     margin-right: 4px;
@@ -159,6 +161,10 @@ export const DropdownStyled = styled.div`
     padding: 3px 8px;
     margin: 0 0 2px 8px;
     border-radius: 4px;
+
+    &.ant-select-item-option-active {
+      background-color: #f2f7fc;
+    }
   }
   .ant-select-item-option-content {
     display: flex;
@@ -193,7 +199,7 @@ const TagEdit = (props: TagEditPropsType) => {
     });
     return result;
   });
-  const [open, setOpen] = useState(true);
+  const [open, setOpen] = useState(false);
   return (
     <Wrapper>
       <CustomSelect
@@ -205,6 +211,7 @@ const TagEdit = (props: TagEditPropsType) => {
         defaultValue={props.value}
         style={{ width: "100%" }}
         open={open}
+        allowClear={true}
         suffixIcon={<PackUpIcon />}
         onSearch={(value: string) => {
           if (defaultTags.findIndex((item) => item.includes(value)) < 0) {
@@ -216,6 +223,7 @@ const TagEdit = (props: TagEditPropsType) => {
         }}
         onChange={(value: string | string[]) => {
           props.onChange(value);
+          setOpen(false)
         }}
         dropdownRender={(originNode: ReactNode) => (
           <DropdownStyled>
@@ -223,11 +231,12 @@ const TagEdit = (props: TagEditPropsType) => {
           </DropdownStyled>
         )}
         dropdownStyle={{ marginTop: "7px", padding: "8px 0 6px 0" }}
-        onBlur={props.onChangeEnd}
-        onKeyDown={(e) => {
-          if (e.key === "Enter") {
-            props.onChangeEnd();
-          }
+        onFocus={() => {
+          setOpen(true);
+        }}
+        onBlur={() => {
+          props.onChangeEnd();
+          setOpen(false);
         }}
         onClick={() => setOpen(!open)}
       >
@@ -259,7 +268,7 @@ export const ColumnTagsComp = (function () {
       tagOptionsList = props.tagColors;
       let value = props.changeValue ?? getBaseValue(props, dispatch);
       value = typeof value === "string" && value.split(",")[1] ? value.split(",") : value;
-      const tags = _.isArray(value) ? value : [value];
+      const tags = _.isArray(value) ? value : (value.length ? [value] : []);
       const view = tags.map((tag, index) => {
         // The actual eval value is of type number or boolean
         const tagText = String(tag);
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx
index 922430fde8..8839c3202f 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx
@@ -45,6 +45,7 @@ export const ButtonComp = (function () {
             loading={props.loading}
             disabled={props.disabled}
             $buttonStyle={props.buttonType === "primary" ? style : undefined}
+            style={{margin: 0}}
           >
             {/* prevent the button from disappearing */}
             {!props.text ? " " : props.text}
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/tableColumnComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/tableColumnComp.tsx
index c9057ed73b..440d6f1e05 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/column/tableColumnComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/tableColumnComp.tsx
@@ -29,6 +29,9 @@ import styled from "styled-components";
 import { TextOverflowControl } from "comps/controls/textOverflowControl";
 import { default as Divider } from "antd/es/divider";
 import { ColumnValueTooltip } from "./simpleColumnTypeComps";
+import { SummaryColumnComp } from "./tableSummaryColumnComp";
+import { list } from "@lowcoder-ee/comps/generators/list";
+import { EMPTY_ROW_KEY } from "../tableCompView";
 export type Render = ReturnType<ConstructorToComp<typeof RenderComp>["getOriginalComp"]>;
 export const RenderComp = withSelectedMultiContext(ColumnTypeComp);
 
@@ -145,6 +148,9 @@ export const columnChildrenMap = {
   linkColor: withDefault(ColorControl, "#3377ff"),
   linkHoverColor: withDefault(ColorControl, ""),
   linkActiveColor: withDefault(ColorControl, ""),
+  summaryColumns: withDefault(list(SummaryColumnComp), [
+    {}, {}, {}
+  ])
 };
 
 const StyledBorderRadiusIcon = styled(IconRadius)` width: 24px; margin: 0 8px 0 -3px; padding: 3px;`;
@@ -230,7 +236,7 @@ export class ColumnComp extends ColumnInitComp {
     });
   }
 
-  propertyView(key: string) {
+  propertyView(key: string, viewMode: string, summaryRowIndex: number) {
     const columnType = this.children.render.getSelectedComp().getComp().children.compType.getView();
     const initialColumns = this.children.render.getSelectedComp().getParams()?.initialColumns as OptionType[] || [];
     const column = this.children.render.getSelectedComp().getComp().toJsonValue();
@@ -241,138 +247,147 @@ export class ColumnComp extends ColumnInitComp {
       columnValue = (column.comp as any).text;
     }
 
+    const summaryColumns = this.children.summaryColumns.getView();
+  
     return (
       <>
-        {this.children.title.propertyView({
-          label: trans("table.columnTitle"),
-          placeholder: this.children.dataIndex.getView(),
-        })}
-        {this.children.titleTooltip.propertyView({
-          label: trans("table.columnTitleTooltip"),
-        })}
-        {this.children.cellTooltip.getPropertyView()}
-        <Dropdown
-          showSearch={true}
-          defaultValue={columnValue}
-          options={initialColumns}
-          label={trans("table.dataMapping")}
-          onChange={(value) => {
-            // Keep the previous text value, some components do not have text, the default value is currentCell
-            const compType = columnType;
-            let comp: Record<string, string> = { text: value};
-            if(columnType === 'image') {
-              comp = { src: value };
-            }
-            this.children.render.dispatchChangeValueAction({
-              compType,
-              comp,
-            } as any);
-          }}
-        />
-        {/* FIXME: cast type currently, return type of withContext should be corrected later */}
-        {this.children.render.getPropertyView()}
-        {this.children.showTitle.propertyView({
-          label: trans("table.showTitle"),
-          tooltip: trans("table.showTitleTooltip"),
-        })}
-        {ColumnTypeCompMap[columnType].canBeEditable() &&
-          this.children.editable.propertyView({ label: trans("table.editable") })}
-        {this.children.sortable.propertyView({
-          label: trans("table.sortable"),
-        })}
-        {this.children.hide.propertyView({
-          label: trans("prop.hide"),
-        })}
-        {this.children.align.propertyView({
-          label: trans("table.align"),
-          radioButton: true,
-        })}
-        {this.children.fixed.propertyView({
-          label: trans("table.fixedColumn"),
-          radioButton: true,
-        })}
-        {this.children.autoWidth.propertyView({
-          label: trans("table.autoWidth"),
-          radioButton: true,
-        })}
-        {this.children.autoWidth.getView() === "fixed" &&
-          this.children.width.propertyView({ label: trans("prop.width") })}
-
-        {(columnType === 'link' || columnType === 'links') && (
+        {viewMode === 'summary' && (
+          summaryColumns[summaryRowIndex].propertyView('')
+        )}
+        {viewMode === 'normal' && (
           <>
+            {this.children.title.propertyView({
+              label: trans("table.columnTitle"),
+              placeholder: this.children.dataIndex.getView(),
+            })}
+            {this.children.titleTooltip.propertyView({
+              label: trans("table.columnTitleTooltip"),
+            })}
+            {this.children.cellTooltip.getPropertyView()}
+            <Dropdown
+              showSearch={true}
+              defaultValue={columnValue}
+              options={initialColumns}
+              label={trans("table.dataMapping")}
+              onChange={(value) => {
+                // Keep the previous text value, some components do not have text, the default value is currentCell
+                const compType = columnType;
+                let comp: Record<string, string> = { text: value};
+                if(columnType === 'image') {
+                  comp = { src: value };
+                }
+                this.children.render.dispatchChangeValueAction({
+                  compType,
+                  comp,
+                } as any);
+              }}
+            />
+            {/* FIXME: cast type currently, return type of withContext should be corrected later */}
+            {this.children.render.getPropertyView()}
+            {this.children.showTitle.propertyView({
+              label: trans("table.showTitle"),
+              tooltip: trans("table.showTitleTooltip"),
+            })}
+            {ColumnTypeCompMap[columnType].canBeEditable() &&
+              this.children.editable.propertyView({ label: trans("table.editable") })}
+            {this.children.sortable.propertyView({
+              label: trans("table.sortable"),
+            })}
+            {this.children.hide.propertyView({
+              label: trans("prop.hide"),
+            })}
+            {this.children.align.propertyView({
+              label: trans("table.align"),
+              radioButton: true,
+            })}
+            {this.children.fixed.propertyView({
+              label: trans("table.fixedColumn"),
+              radioButton: true,
+            })}
+            {this.children.autoWidth.propertyView({
+              label: trans("table.autoWidth"),
+              radioButton: true,
+            })}
+            {this.children.autoWidth.getView() === "fixed" &&
+              this.children.width.propertyView({ label: trans("prop.width") })}
+
+            {(columnType === 'link' || columnType === 'links') && (
+              <>
+                <Divider style={{ margin: '12px 0' }} />
+                {controlItem({}, (
+                  <div>
+                    <b>{"Link Style"}</b>
+                  </div>
+                ))}
+                {this.children.linkColor.propertyView({
+                  label: trans('text') // trans('style.background'),
+                })}
+                {this.children.linkHoverColor.propertyView({
+                  label: "Hover text", // trans('style.background'),
+                })}
+                {this.children.linkActiveColor.propertyView({
+                  label: "Active text", // trans('style.background'),
+                })}
+              </>
+            )}
             <Divider style={{ margin: '12px 0' }} />
             {controlItem({}, (
               <div>
-                <b>{"Link Style"}</b>
+                <b>{"Column Style"}</b>
               </div>
             ))}
-            {this.children.linkColor.propertyView({
-              label: trans('text') // trans('style.background'),
+            {this.children.background.propertyView({
+              label: trans('style.background'),
             })}
-            {this.children.linkHoverColor.propertyView({
-              label: "Hover text", // trans('style.background'),
+            {columnType !== 'link' && this.children.text.propertyView({
+              label: trans('text'),
             })}
-            {this.children.linkActiveColor.propertyView({
-              label: "Active text", // trans('style.background'),
+            {this.children.border.propertyView({
+              label: trans('style.border')
             })}
+            {this.children.borderWidth.propertyView({
+              label: trans('style.borderWidth'),
+              preInputNode: <StyledBorderIcon as={BorderWidthIcon} title="" />,
+              placeholder: '1px',
+            })}
+            {this.children.radius.propertyView({
+              label: trans('style.borderRadius'),
+              preInputNode: <StyledBorderRadiusIcon as={IconRadius} title="" />,
+              placeholder: '3px',
+            })}
+            {this.children.textSize.propertyView({
+              label: trans('style.textSize'),
+              preInputNode: <StyledTextSizeIcon as={TextSizeIcon} title="" />,
+              placeholder: '14px',
+            })}
+            {this.children.textWeight.propertyView({
+              label: trans('style.textWeight'),
+              preInputNode: <StyledTextWeightIcon as={TextWeightIcon} title="" />,
+              placeholder: 'normal',
+            })}
+            {this.children.fontFamily.propertyView({
+              label: trans('style.fontFamily'),
+              preInputNode: <StyledFontFamilyIcon as={FontFamilyIcon} title="" />,
+              placeholder: 'sans-serif',
+            })}
+            {this.children.fontStyle.propertyView({
+              label: trans('style.fontStyle'),
+              preInputNode: <StyledFontFamilyIcon as={FontFamilyIcon} title="" />,
+              placeholder: 'normal'
+            })}
+            {this.children.textOverflow.getPropertyView()}
+            {this.children.cellColor.getPropertyView()}
           </>
         )}
-        <Divider style={{ margin: '12px 0' }} />
-        {controlItem({}, (
-          <div>
-            <b>{"Column Style"}</b>
-          </div>
-        ))}
-        {this.children.background.propertyView({
-          label: trans('style.background'),
-        })}
-        {columnType !== 'link' && this.children.text.propertyView({
-          label: trans('text'),
-        })}
-        {this.children.border.propertyView({
-          label: trans('style.border')
-        })}
-        {this.children.borderWidth.propertyView({
-          label: trans('style.borderWidth'),
-          preInputNode: <StyledBorderIcon as={BorderWidthIcon} title="" />,
-          placeholder: '1px',
-        })}
-        {this.children.radius.propertyView({
-          label: trans('style.borderRadius'),
-          preInputNode: <StyledBorderRadiusIcon as={IconRadius} title="" />,
-          placeholder: '3px',
-        })}
-        {this.children.textSize.propertyView({
-          label: trans('style.textSize'),
-          preInputNode: <StyledTextSizeIcon as={TextSizeIcon} title="" />,
-          placeholder: '14px',
-        })}
-        {this.children.textWeight.propertyView({
-          label: trans('style.textWeight'),
-          preInputNode: <StyledTextWeightIcon as={TextWeightIcon} title="" />,
-          placeholder: 'normal',
-        })}
-        {this.children.fontFamily.propertyView({
-          label: trans('style.fontFamily'),
-          preInputNode: <StyledFontFamilyIcon as={FontFamilyIcon} title="" />,
-          placeholder: 'sans-serif',
-        })}
-        {this.children.fontStyle.propertyView({
-          label: trans('style.fontStyle'),
-          preInputNode: <StyledFontFamilyIcon as={FontFamilyIcon} title="" />,
-          placeholder: 'normal'
-        })}
-        {this.children.textOverflow.getPropertyView()}
-        {this.children.cellColor.getPropertyView()}
       </>
     );
   }
 
   getChangeSet() {
     const dataIndex = this.children.dataIndex.getView();
-    const changeSet = _.mapValues(this.children.render.getMap(), (value) =>
-      value.getComp().children.comp.children.changeValue.getView()
-    );
+    const changeSet = _.mapValues(this.children.render.getMap(), (value) =>{
+     return value.getComp().children.comp.children.changeValue.getView()
+    });
     return { [dataIndex]: changeSet };
   }
 
@@ -389,6 +404,15 @@ export class ColumnComp extends ColumnInitComp {
     );
   }
 
+  dispatchClearInsertSet() {
+    const renderMap = this.children.render.getMap();
+    const insertMapKeys = Object.keys(renderMap).filter(key => key.startsWith(EMPTY_ROW_KEY));
+    insertMapKeys.forEach(key => {
+      const render = renderMap[key];
+      render.getComp().children.comp.children.changeValue.dispatchChangeValueAction(null);
+    });
+  }
+
   static setSelectionAction(key: string) {
     return wrapChildAction("render", RenderComp.setSelectionAction(key));
   }
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/tableColumnListComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/tableColumnListComp.tsx
index 4a3c5237b5..2c7d9df3e6 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/column/tableColumnListComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/tableColumnListComp.tsx
@@ -17,6 +17,7 @@ import {
 import { shallowEqual } from "react-redux";
 import { JSONObject, JSONValue } from "util/jsonTypes";
 import { lastValueIfEqual } from "util/objectUtils";
+import { EMPTY_ROW_KEY } from "../tableCompView";
 
 /**
  * column list
@@ -70,14 +71,17 @@ export class ColumnListComp extends ColumnListTmpComp {
     return super.reduce(action);
   }
 
-  getChangeSet() {
+  getChangeSet(filterNewRowsChange?: boolean) {
     const changeSet: Record<string, Record<string, JSONValue>> = {};
     const columns = this.getView();
     columns.forEach((column) => {
       const columnChangeSet = column.getChangeSet();
       Object.keys(columnChangeSet).forEach((dataIndex) => {
         Object.keys(columnChangeSet[dataIndex]).forEach((key) => {
-          if (!_.isNil(columnChangeSet[dataIndex][key])) {
+          const includeChange = filterNewRowsChange
+            ? key.startsWith(EMPTY_ROW_KEY)
+            : !key.startsWith(EMPTY_ROW_KEY);
+          if (!_.isNil(columnChangeSet[dataIndex][key]) && includeChange) {
             if (!changeSet[key]) changeSet[key] = {};
             changeSet[key][dataIndex] = columnChangeSet[dataIndex][key];
           }
@@ -92,6 +96,11 @@ export class ColumnListComp extends ColumnListTmpComp {
     columns.forEach((column) => column.dispatchClearChangeSet());
   }
 
+  dispatchClearInsertSet() {
+    const columns = this.getView();
+    columns.forEach((column) => column.dispatchClearInsertSet());
+  }
+
   /**
    * If the table data changes, call this method to trigger the action
    */
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/tableSummaryColumnComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/tableSummaryColumnComp.tsx
new file mode 100644
index 0000000000..13f4f2d5b8
--- /dev/null
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/tableSummaryColumnComp.tsx
@@ -0,0 +1,205 @@
+import { RadiusControl, StringControl } from "comps/controls/codeControl";
+import { HorizontalAlignmentControl } from "comps/controls/dropdownControl";
+import { MultiCompBuilder, valueComp, withDefault } from "comps/generators";
+import { withSelectedMultiContext } from "comps/generators/withSelectedMultiContext";
+import { trans } from "i18n";
+import _ from "lodash";
+import {
+  changeChildAction,
+  CompAction,
+  ConstructorToComp,
+  deferAction,
+  fromRecord,
+  withFunction,
+  wrapChildAction,
+} from "lowcoder-core";
+import { IconRadius, TextSizeIcon, FontFamilyIcon, TextWeightIcon, controlItem } from "lowcoder-design";
+import { ColumnTypeComp } from "./columnTypeComp";
+import { ColorControl } from "comps/controls/colorControl";
+import styled from "styled-components";
+import { TextOverflowControl } from "comps/controls/textOverflowControl";
+import { default as Divider } from "antd/es/divider";
+export type Render = ReturnType<ConstructorToComp<typeof RenderComp>["getOriginalComp"]>;
+export const RenderComp = withSelectedMultiContext(ColumnTypeComp);
+
+export const columnChildrenMap = {
+  cellTooltip: StringControl,
+  // a custom column or a data column
+  isCustom: valueComp<boolean>(false),
+  // If it is a data column, it must be the name of the column and cannot be duplicated as a react key
+  dataIndex: valueComp<string>(""),
+  render: RenderComp,
+  align: HorizontalAlignmentControl,
+  background: withDefault(ColorControl, ""),
+  margin: withDefault(RadiusControl, ""),
+  text: withDefault(ColorControl, ""),
+  border: withDefault(ColorControl, ""),
+  radius: withDefault(RadiusControl, ""),
+  textSize: withDefault(RadiusControl, ""),
+  textWeight: withDefault(StringControl, "normal"),
+  fontFamily: withDefault(StringControl, "sans-serif"),
+  fontStyle: withDefault(StringControl, 'normal'),
+  cellColor: StringControl,
+  textOverflow: withDefault(TextOverflowControl, "ellipsis"),
+  linkColor: withDefault(ColorControl, "#3377ff"),
+  linkHoverColor: withDefault(ColorControl, ""),
+  linkActiveColor: withDefault(ColorControl, ""),
+};
+
+const StyledBorderRadiusIcon = styled(IconRadius)` width: 24px; margin: 0 8px 0 -3px; padding: 3px;`;
+const StyledTextSizeIcon = styled(TextSizeIcon)` width: 24px; margin: 0 8px 0 -3px; padding: 3px;`;
+const StyledFontFamilyIcon = styled(FontFamilyIcon)` width: 24px; margin: 0 8px 0 -3px; padding: 3px;`;
+const StyledTextWeightIcon = styled(TextWeightIcon)` width: 24px; margin: 0 8px 0 -3px; padding: 3px;`;
+
+/**
+ * export for test.
+ * Put it here temporarily to avoid circular dependencies
+ */
+const ColumnInitComp = new MultiCompBuilder(columnChildrenMap, (props, dispatch) => {
+  return {
+    ...props,
+  };
+})
+  .setPropertyViewFn(() => <></>)
+  .build();
+
+export class SummaryColumnComp extends ColumnInitComp {
+  override reduce(action: CompAction) {
+    const comp = super.reduce(action);
+    return comp;
+  }
+
+  override getView() {
+    const superView = super.getView();
+    const columnType = this.children.render.getSelectedComp().getComp().children.compType.getView();
+    return {
+      ...superView,
+      columnType,
+    };
+  }
+
+  exposingNode() {
+    const dataIndexNode = this.children.dataIndex.exposingNode();
+
+    const renderNode = withFunction(this.children.render.node(), (render) => ({
+      wrap: render.__comp__.wrap,
+      map: _.mapValues(render.__map__, (value) => value.comp),
+    }));
+    return fromRecord({
+      dataIndex: dataIndexNode,
+      render: renderNode,
+    });
+  }
+
+  propertyView(key: string) {
+    const columnType = this.children.render.getSelectedComp().getComp().children.compType.getView();
+    const column = this.children.render.getSelectedComp().getComp().toJsonValue();
+    let columnValue = '{{currentCell}}';
+    if (column.comp?.hasOwnProperty('src')) {
+      columnValue = (column.comp as any).src;
+    } else if (column.comp?.hasOwnProperty('text')) {
+      columnValue = (column.comp as any).text;
+    }
+
+    return (
+      <>
+        {this.children.cellTooltip.propertyView({
+          label: trans("table.columnTooltip"),
+        })}
+        {this.children.render.getPropertyView()}
+        {this.children.align.propertyView({
+          label: trans("table.align"),
+          radioButton: true,
+        })}
+        {(columnType === 'link' || columnType === 'links') && (
+          <>
+            <Divider style={{ margin: '12px 0' }} />
+            {controlItem({}, (
+              <div>
+                <b>{"Link Style"}</b>
+              </div>
+            ))}
+            {this.children.linkColor.propertyView({
+              label: trans('text')
+            })}
+            {this.children.linkHoverColor.propertyView({
+              label: "Hover text",
+            })}
+            {this.children.linkActiveColor.propertyView({
+              label: "Active text",
+            })}
+          </>
+        )}
+        <Divider style={{ margin: '12px 0' }} />
+        {controlItem({}, (
+          <div>
+            <b>{"Column Style"}</b>
+          </div>
+        ))}
+        {this.children.background.propertyView({
+          label: trans('style.background'),
+        })}
+        {columnType !== 'link' && this.children.text.propertyView({
+          label: trans('text'),
+        })}
+        {this.children.border.propertyView({
+          label: trans('style.border')
+        })}
+        {this.children.radius.propertyView({
+          label: trans('style.borderRadius'),
+          preInputNode: <StyledBorderRadiusIcon as={IconRadius} title="" />,
+          placeholder: '3px',
+        })}
+        {this.children.textSize.propertyView({
+          label: trans('style.textSize'),
+          preInputNode: <StyledTextSizeIcon as={TextSizeIcon} title="" />,
+          placeholder: '14px',
+        })}
+        {this.children.textWeight.propertyView({
+          label: trans('style.textWeight'),
+          preInputNode: <StyledTextWeightIcon as={TextWeightIcon} title="" />,
+          placeholder: 'normal',
+        })}
+        {this.children.fontFamily.propertyView({
+          label: trans('style.fontFamily'),
+          preInputNode: <StyledFontFamilyIcon as={FontFamilyIcon} title="" />,
+          placeholder: 'sans-serif',
+        })}
+        {this.children.fontStyle.propertyView({
+          label: trans('style.fontStyle'),
+          preInputNode: <StyledFontFamilyIcon as={FontFamilyIcon} title="" />,
+          placeholder: 'normal'
+        })}
+        {/* {this.children.textOverflow.getPropertyView()} */}
+        {this.children.cellColor.propertyView({
+          label: trans("table.cellColor"),
+        })}
+      </>
+    );
+  }
+
+  getChangeSet() {
+    const dataIndex = this.children.dataIndex.getView();
+    const changeSet = _.mapValues(this.children.render.getMap(), (value) =>
+      value.getComp().children.comp.children.changeValue.getView()
+    );
+    return { [dataIndex]: changeSet };
+  }
+
+  dispatchClearChangeSet() {
+    this.children.render.dispatch(
+      deferAction(
+        RenderComp.forEachAction(
+          wrapChildAction(
+            "comp",
+            wrapChildAction("comp", changeChildAction("changeValue", null, false))
+          )
+        )
+      )
+    );
+  }
+
+  static setSelectionAction(key: string) {
+    return wrapChildAction("render", RenderComp.setSelectionAction(key));
+  }
+}
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/tableComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/tableComp.tsx
index 553a36a0da..0d1abdd0a1 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/tableComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/tableComp.tsx
@@ -1,6 +1,6 @@
 import { tableDataRowExample } from "comps/comps/tableComp/column/tableColumnListComp";
 import { getPageSize } from "comps/comps/tableComp/paginationControl";
-import { TableCompView } from "comps/comps/tableComp/tableCompView";
+import { EMPTY_ROW_KEY, TableCompView } from "comps/comps/tableComp/tableCompView";
 import { TableFilter } from "comps/comps/tableComp/tableToolbarComp";
 import {
   columnHide,
@@ -40,7 +40,11 @@ import {
   deferAction,
   executeQueryAction,
   fromRecord,
+  FunctionNode,
+  Node,
   onlyEvalAction,
+  RecordNode,
+  RecordNodeToValue,
   routeByNameAction,
   withFunction,
   wrapChildAction,
@@ -53,7 +57,7 @@ import { getSelectedRowKeys } from "./selectionControl";
 import { compTablePropertyView } from "./tablePropertyView";
 import { RowColorComp, RowHeightComp, TableChildrenView, TableInitComp } from "./tableTypes";
 
-import { useContext } from "react";
+import { useContext, useState } from "react";
 import { EditorContext } from "comps/editorState";
 
 export class TableImplComp extends TableInitComp implements IContainer {
@@ -386,12 +390,11 @@ export class TableImplComp extends TableInitComp implements IContainer {
     )[0];
   }
 
-  changeSetNode() {
-    const nodes = {
-      dataIndexes: this.children.columns.getColumnsNode("dataIndex"),
-      renders: this.children.columns.getColumnsNode("render"),
-    };
-    const resNode = withFunction(fromRecord(nodes), (input) => {
+  private getUpsertSetResNode(
+    nodes: Record<string, RecordNode<Record<string, Node<any>>>>,
+    filterNewRows?: boolean,
+  ) {
+    return withFunction(fromRecord(nodes), (input) => {
       // merge input.dataIndexes and input.withParams into one structure
       const dataIndexRenderDict = _(input.dataIndexes)
         .mapValues((dataIndex, idx) => input.renders[idx])
@@ -401,7 +404,8 @@ export class TableImplComp extends TableInitComp implements IContainer {
       _.forEach(dataIndexRenderDict, (render, dataIndex) => {
         _.forEach(render[MAP_KEY], (value, key) => {
           const changeValue = (value.comp as any).comp.changeValue;
-          if (!_.isNil(changeValue)) {
+          const includeRecord = (filterNewRows && key.startsWith(EMPTY_ROW_KEY)) || (!filterNewRows && !key.startsWith(EMPTY_ROW_KEY));
+          if (!_.isNil(changeValue) && includeRecord) {
             if (!record[key]) record[key] = {};
             record[key][dataIndex] = changeValue;
           }
@@ -409,18 +413,36 @@ export class TableImplComp extends TableInitComp implements IContainer {
       });
       return record;
     });
+  }
+
+  changeSetNode() {
+    const nodes = {
+      dataIndexes: this.children.columns.getColumnsNode("dataIndex"),
+      renders: this.children.columns.getColumnsNode("render"),
+    };
+
+    const resNode = this.getUpsertSetResNode(nodes);
     return lastValueIfEqual(this, "changeSetNode", [resNode, nodes] as const, (a, b) =>
       shallowEqual(a[1], b[1])
     )[0];
   }
 
-  toUpdateRowsNode() {
+  insertSetNode() {
     const nodes = {
-      oriDisplayData: this.oriDisplayDataNode(),
-      indexes: this.displayDataIndexesNode(),
-      changeSet: this.changeSetNode(),
+      dataIndexes: this.children.columns.getColumnsNode("dataIndex"),
+      renders: this.children.columns.getColumnsNode("render"),
     };
-    const resNode = withFunction(fromRecord(nodes), (input) => {
+
+    const resNode = this.getUpsertSetResNode(nodes, true);
+    return lastValueIfEqual(this, "insertSetNode", [resNode, nodes] as const, (a, b) =>
+      shallowEqual(a[1], b[1])
+    )[0];
+  }
+
+  private getToUpsertRowsResNodes(
+    nodes: Record<string, FunctionNode<any, any>>
+  ) {
+    return withFunction(fromRecord(nodes), (input) => {
       const res = _(input.changeSet)
         .map((changeValues, oriIndex) => {
           const idx = input.indexes[oriIndex];
@@ -431,11 +453,34 @@ export class TableImplComp extends TableInitComp implements IContainer {
       // console.info("toUpdateRowsNode. input: ", input, " res: ", res);
       return res;
     });
+  }
+
+  toUpdateRowsNode() {
+    const nodes = {
+      oriDisplayData: this.oriDisplayDataNode(),
+      indexes: this.displayDataIndexesNode(),
+      changeSet: this.changeSetNode(),
+    };
+
+    const resNode = this.getToUpsertRowsResNodes(nodes);
     return lastValueIfEqual(this, "toUpdateRowsNode", [resNode, nodes] as const, (a, b) =>
       shallowEqual(a[1], b[1])
     )[0];
   }
 
+  toInsertRowsNode() {
+    const nodes = {
+      oriDisplayData: this.oriDisplayDataNode(),
+      indexes: this.displayDataIndexesNode(),
+      changeSet: this.insertSetNode(),
+    };
+
+    const resNode = this.getToUpsertRowsResNodes(nodes);
+    return lastValueIfEqual(this, "toInsertRowsNode", [resNode, nodes] as const, (a, b) =>
+      shallowEqual(a[1], b[1])
+    )[0];
+  }
+
   columnAggrNode() {
     const nodes = {
       oriDisplayData: this.oriDisplayDataNode(),
@@ -458,6 +503,7 @@ export class TableImplComp extends TableInitComp implements IContainer {
 }
 
 let TableTmpComp = withViewFn(TableImplComp, (comp) => {
+  const [emptyRows, setEmptyRows] = useState([]);
   return (
     <HidableView hidden={comp.children.hidden.getView()}>
       <TableCompView
@@ -672,6 +718,14 @@ export const TableComp = withExposingConfigs(TableTmpComp, [
     (input) => input.changeSet,
     trans("table.changeSetDesc")
   ),
+  new CompDepsConfig(
+    "insertSet",
+    (comp) => ({
+      insertSet: comp.insertSetNode(),
+    }),
+    (input) => input.insertSet,
+    trans("table.changeSetDesc")
+  ),
   new CompDepsConfig(
     "toUpdateRows",
     (comp) => ({
@@ -682,6 +736,16 @@ export const TableComp = withExposingConfigs(TableTmpComp, [
     },
     trans("table.toUpdateRowsDesc")
   ),
+  new CompDepsConfig(
+    "toInsertRows",
+    (comp) => ({
+      toInsertRows: comp.toInsertRowsNode(),
+    }),
+    (input) => {
+      return input.toInsertRows;
+    },
+    trans("table.toUpdateRowsDesc")
+  ),
   new DepsConfig(
     "pageNo",
     (children) => {
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/tableCompView.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/tableCompView.tsx
index 3bb8403e94..9861d5a23e 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/tableCompView.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/tableCompView.tsx
@@ -5,6 +5,7 @@ import { RowColorViewType, RowHeightViewType, TableEventOptionValues } from "com
 import {
   COL_MIN_WIDTH,
   COLUMN_CHILDREN_KEY,
+  ColumnsAggrData,
   columnsToAntdFormat,
   CustomColumnType,
   OB_ROW_ORI_INDEX,
@@ -39,10 +40,13 @@ import { SlotConfigContext } from "comps/controls/slotControl";
 import { EmptyContent } from "pages/common/styledComponent";
 import { messageInstance } from "lowcoder-design/src/components/GlobalInstances";
 import { ReactRef, ResizeHandleAxis } from "layout/gridLayoutPropTypes";
-import { CellColorViewType } from "./column/tableColumnComp";
+import { CellColorViewType, ColumnComp } from "./column/tableColumnComp";
 import { defaultTheme } from "@lowcoder-ee/constants/themeConstants";
 import { childrenToProps } from "@lowcoder-ee/comps/generators/multi";
 import { getVerticalMargin } from "@lowcoder-ee/util/cssUtil";
+import { TableSummary } from "./tableSummaryComp";
+
+export const EMPTY_ROW_KEY = 'empty_row';
 
 function genLinerGradient(color: string) {
   return `linear-gradient(${color}, ${color})`;
@@ -321,15 +325,6 @@ const TableWrapper = styled.div<{
             border-top-right-radius: 0px;
           }
         }
-
-        // hide the bottom border of the last row
-        ${(props) =>
-    props.$toolbarPosition !== "below" &&
-    `
-            tbody > tr:last-child > td {
-              border-bottom: unset;
-            }
-        `}
       }
 
       .ant-table-expanded-row-fixed:after {
@@ -376,8 +371,11 @@ const TableTd = styled.td<{
   border-radius: ${(props) => props.$style.radius};
   padding: 0 !important;
 
-  > div {
-    margin: ${(props) => props.$style.margin};
+  > div:not(.editing-border, .editing-wrapper),
+  .editing-wrapper .ant-input,
+  .editing-wrapper .ant-input-number,
+  .editing-wrapper .ant-picker {
+    margin: ${(props) => props.$isEditing ? '0px' : props.$style.margin};
     color: ${(props) => props.$style.text};
     font-weight: ${(props) => props.$style.textWeight};
     font-family: ${(props) => props.$style.fontFamily};
@@ -385,7 +383,7 @@ const TableTd = styled.td<{
     ${(props) => props.$tableSize === 'small' && `
       padding: 1px 8px;
       font-size: ${props.$defaultThemeDetail.textSize == props.$style.textSize ? '14px !important' : props.$style.textSize + ' !important'};
-    font-style:${props.$style.fontStyle} !important;
+      font-style:${props.$style.fontStyle} !important;
       min-height: ${props.$style.rowHeight || '14px'};
       line-height: 20px;
       ${!props.$autoHeight && `
@@ -596,7 +594,7 @@ function TableCellView(props: {
       </TableTd>
     );
   }
- 
+
   return (
     <TableCellContext.Provider value={{ isEditing: editing, setIsEditing: setEditing }}>
       {tdView}
@@ -714,11 +712,25 @@ function ResizeableTable<RecordType extends object>(props: CustomTableProps<Reco
 
 ResizeableTable.whyDidYouRender = true;
 
+const createNewEmptyRow = (
+  rowIndex: number,
+  columnsAggrData: ColumnsAggrData,
+) => {
+  const emptyRowData: RecordType = {
+    [OB_ROW_ORI_INDEX]: `${EMPTY_ROW_KEY}_${rowIndex}`,
+  };
+  Object.keys(columnsAggrData).forEach(columnKey => {
+    emptyRowData[columnKey] = '';
+  });
+  return emptyRowData;
+}
+
 export function TableCompView(props: {
   comp: InstanceType<typeof TableImplComp>;
   onRefresh: (allQueryNames: Array<string>, setLoading: (loading: boolean) => void) => void;
   onDownload: (fileName: string) => void;
 }) {
+  const [emptyRowsMap, setEmptyRowsMap] = useState<Record<string, RecordType>>({});
   const editorState = useContext(EditorContext);
   const { width, ref } = useResizeDetector({
     refreshMode: "debounce",
@@ -741,15 +753,21 @@ export function TableCompView(props: {
   const visibleResizables = compChildren.visibleResizables.getView();
   const showHRowGridBorder = compChildren.showHRowGridBorder.getView();
   const columnsStyle = compChildren.columnsStyle.getView();
+  const summaryRowStyle = compChildren.summaryRowStyle.getView();
   const changeSet = useMemo(() => compChildren.columns.getChangeSet(), [compChildren.columns]);
-  const hasChange = useMemo(() => !_.isEmpty(changeSet), [changeSet]);
+  const insertSet = useMemo(() => compChildren.columns.getChangeSet(true), [compChildren.columns]);
+  const hasChange = useMemo(() => !_.isEmpty(changeSet) || !_.isEmpty(insertSet), [changeSet, insertSet]);
   const columns = useMemo(() => compChildren.columns.getView(), [compChildren.columns]);
   const columnViews = useMemo(() => columns.map((c) => c.getView()), [columns]);
   const data = comp.filterData;
   const sort = useMemo(() => compChildren.sort.getView(), [compChildren.sort]);
   const toolbar = useMemo(() => compChildren.toolbar.getView(), [compChildren.toolbar]);
+  const showSummary = useMemo(() => compChildren.showSummary.getView(), [compChildren.showSummary]);
+  const summaryRows = useMemo(() => compChildren.summaryRows.getView(), [compChildren.summaryRows]);
+  const inlineAddNewRow = useMemo(() => compChildren.inlineAddNewRow.getView(), [compChildren.inlineAddNewRow]);
   const pagination = useMemo(() => compChildren.pagination.getView(), [compChildren.pagination]);
   const size = useMemo(() => compChildren.size.getView(), [compChildren.size]);
+  const editModeClicks = useMemo(() => compChildren.editModeClicks.getView(), [compChildren.editModeClicks]);
   const onEvent = useMemo(() => compChildren.onEvent.getView(), [compChildren.onEvent]);
   const dynamicColumn = compChildren.dynamicColumn.getView();
   const dynamicColumnConfig = useMemo(
@@ -768,6 +786,7 @@ export function TableCompView(props: {
         dynamicColumn,
         dynamicColumnConfig,
         columnsAggrData,
+        editModeClicks,
         onEvent,
       ),
     [
@@ -778,13 +797,78 @@ export function TableCompView(props: {
       dynamicColumn,
       dynamicColumnConfig,
       columnsAggrData,
+      editModeClicks,
     ]
   );
+
   const supportChildren = useMemo(
     () => supportChildrenTree(compChildren.data.getView()),
     [compChildren.data]
   );
 
+  const updateEmptyRows = useCallback(() => {
+    if (!inlineAddNewRow) {
+      setEmptyRowsMap({})
+      setTimeout(() => compChildren.columns.dispatchClearInsertSet());
+      return;
+    }
+
+    let emptyRows: Record<string, RecordType> = {...emptyRowsMap};
+    const existingRowsKeys = Object.keys(emptyRows);
+    const existingRowsCount = existingRowsKeys.length;
+    const updatedRowsKeys = Object.keys(insertSet).filter(
+      key => key.startsWith(EMPTY_ROW_KEY)
+    );
+    const updatedRowsCount = updatedRowsKeys.length;
+    const removedRowsKeys = existingRowsKeys.filter(
+      x => !updatedRowsKeys.includes(x)
+    );
+
+    if (removedRowsKeys.length === existingRowsCount) {
+      const newRowIndex = 0;
+      const newRowKey = `${EMPTY_ROW_KEY}_${newRowIndex}`;
+      setEmptyRowsMap({
+        [newRowKey]: createNewEmptyRow(newRowIndex, columnsAggrData)
+      });
+      const ele = document.querySelector<HTMLElement>(`[data-row-key=${newRowKey}]`);
+      if (ele) {
+        ele.style.display = '';
+      }
+      return;
+    }
+
+    removedRowsKeys.forEach(rowKey => {
+      if (
+        rowKey === existingRowsKeys[existingRowsCount - 1]
+        || rowKey === existingRowsKeys[existingRowsCount - 2]
+      ) {
+        delete emptyRows[rowKey];
+      } else {
+        const ele = document.querySelector<HTMLElement>(`[data-row-key=${rowKey}]`);
+        if (ele) {
+          ele.style.display = 'none';
+        }
+      }
+    })
+    const lastRowKey = updatedRowsCount ? updatedRowsKeys[updatedRowsCount - 1] : '';
+    const lastRowIndex = lastRowKey ? parseInt(lastRowKey.replace(`${EMPTY_ROW_KEY}_`, '')) : -1;
+
+    const newRowIndex = lastRowIndex + 1;
+    const newRowKey = `${EMPTY_ROW_KEY}_${newRowIndex}`;
+    emptyRows[newRowKey] = createNewEmptyRow(newRowIndex, columnsAggrData);
+    setEmptyRowsMap(emptyRows);
+  }, [
+    inlineAddNewRow,
+    JSON.stringify(insertSet),
+    setEmptyRowsMap,
+    createNewEmptyRow,
+  ]);
+
+  useEffect(() => {
+    updateEmptyRows();
+  }, [updateEmptyRows]);
+
+
   const pageDataInfo = useMemo(() => {
     // Data pagination
     let pagedData = data;
@@ -799,6 +883,7 @@ export function TableCompView(props: {
       }
       pagedData = pagedData.slice(offset, offset + pagination.pageSize);
     }
+
     return {
       total: total,
       current: current,
@@ -842,11 +927,30 @@ export function TableCompView(props: {
       }}
       hasChange={hasChange}
       onSaveChanges={() => handleChangeEvent("saveChanges")}
-      onCancelChanges={() => handleChangeEvent("cancelChanges")}
+      onCancelChanges={() => {
+        handleChangeEvent("cancelChanges");
+        if (inlineAddNewRow) {
+          setEmptyRowsMap({});
+        }
+      }}
       onEvent={onEvent}
     />
   );
 
+  const summaryView = () => {
+    if (!showSummary) return undefined;
+    return (
+      <TableSummary
+        tableSize={size}
+        istoolbarPositionBelow={toolbar.position === "below"}
+        expandableRows={Boolean(expansion.expandModalView)}
+        summaryRows={parseInt(summaryRows)}
+        columns={columns}
+        summaryRowStyle={summaryRowStyle}
+      />
+    );
+  }
+
   if (antdColumns.length === 0) {
     return <EmptyContent text={trans("table.emptyColumns")} />;
   }
@@ -896,6 +1000,7 @@ export function TableCompView(props: {
                   }
                 }
               }}
+              // rowKey={OB_ROW_ORI_INDEX}
               rowColorFn={compChildren.rowColor.getView() as any}
               rowHeightFn={compChildren.rowHeight.getView() as any}
               {...compChildren.selection.getView()(onEvent)}
@@ -908,7 +1013,7 @@ export function TableCompView(props: {
               columnsStyle={columnsStyle}
               viewModeResizable={compChildren.viewModeResizable.getView()}
               visibleResizables={compChildren.visibleResizables.getView()}
-              dataSource={pageDataInfo.data}
+              dataSource={pageDataInfo.data.concat(Object.values(emptyRowsMap))}
               size={compChildren.size.getView()}
               rowAutoHeight={rowAutoHeight}
               tableLayout="fixed"
@@ -925,8 +1030,8 @@ export function TableCompView(props: {
                   dataIndex: dataIndex,
                 });
               }}
+              summary={summaryView}
             />
-
             <SlotConfigContext.Provider value={{ modalWidth: width && Math.max(width, 300) }}>
               {expansion.expandModalView}
             </SlotConfigContext.Provider>
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/tableDynamicColumn.test.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/tableDynamicColumn.test.tsx
index 022e0558be..d38cdb9877 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/tableDynamicColumn.test.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/tableDynamicColumn.test.tsx
@@ -45,6 +45,7 @@ const expectColumn = (
       comp.children.dynamicColumn.getView(),
       dynamicColumnConfig,
       comp.columnAggrData,
+      comp.children.editModeClicks.getView(),
       onEvent,
     );
     expect(columnViews.length).toBeGreaterThanOrEqual(antdColumns.length);
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/tablePropertyView.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/tablePropertyView.tsx
index 636721c1f3..fff48e6fed 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/tablePropertyView.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/tablePropertyView.tsx
@@ -33,7 +33,7 @@ import React, { useMemo, useState } from "react";
 import { GreyTextColor } from "constants/style";
 import { alignOptions } from "comps/controls/dropdownControl";
 import { ColumnTypeCompMap } from "comps/comps/tableComp/column/columnTypeComp";
-import { changeChildAction } from "lowcoder-core";
+import Segmented from "antd/es/segmented";
 
 const InsertDiv = styled.div`
   display: flex;
@@ -104,6 +104,34 @@ const ColumnBatchOptionWrapper = styled.div`
   font-size: 13px;
 `;
 
+type ViewOptionType = "normal" | "summary";
+
+const summaryRowOptions = [
+  {
+    label: "Row 1",
+    value: 0,
+  },
+  {
+    label: "Row 2",
+    value: 1,
+  },
+  {
+    label: "Row 3",
+    value: 2,
+  },
+];
+
+const columnViewOptions = [
+  {
+    label: "Normal",
+    value: "normal",
+  },
+  {
+    label: "Summary",
+    value: "summary",
+  },
+];
+
 const columnFilterOptions = [
   { label: trans("table.allColumn"), value: "all" },
   { label: trans("table.visibleColumn"), value: "visible" },
@@ -249,6 +277,8 @@ function ColumnPropertyView<T extends MultiBaseComp<TableChildrenType>>(props: {
   comp: T;
   columnLabel: string;
 }) {
+  const [viewMode, setViewMode] = useState('normal');
+  const [summaryRow, setSummaryRow] = useState(0);
   const { comp } = props;
   const selection = getSelectedRowKeys(comp.children.selection)[0] ?? "0";
   const [columnFilterType, setColumnFilterType] = useState<ColumnFilterOptionValueType>("all");
@@ -261,6 +291,7 @@ function ColumnPropertyView<T extends MultiBaseComp<TableChildrenType>>(props: {
     () => columns.filter((c) => columnFilterType === "all" || !c.children.hide.getView()),
     [columnFilterType, columns]
   );
+  const summaryRows = parseInt(comp.children.summaryRows.getView());
 
   const columnOptionToolbar = (
     <InsertDiv>
@@ -365,7 +396,21 @@ function ColumnPropertyView<T extends MultiBaseComp<TableChildrenType>>(props: {
         }}
         content={(column, index) => (
           <>
-            {column.propertyView(selection)}
+            <Segmented
+              block
+              options={columnViewOptions}
+              value={viewMode}
+              onChange={(k) => setViewMode(k as ViewOptionType)}
+            />
+            {viewMode === 'summary' && (
+              <Segmented
+                block
+                options={summaryRowOptions.slice(0, summaryRows)}
+                value={summaryRow}
+                onChange={(k) => setSummaryRow(k)}
+              />
+            )}
+            {column.propertyView(selection, viewMode, summaryRow)}
             {column.getView().isCustom && (
               <RedButton
                 onClick={() => {
@@ -418,6 +463,7 @@ function columnPropertyView<T extends MultiBaseComp<TableChildrenType>>(comp: T)
 export function compTablePropertyView<T extends MultiBaseComp<TableChildrenType> & { editorModeStatus: string }>(comp: T) {
   const editorModeStatus = comp.editorModeStatus;
   const dataLabel = trans("data");
+
   return (
     <>
       {["logic", "both"].includes(editorModeStatus) && (
@@ -448,6 +494,16 @@ export function compTablePropertyView<T extends MultiBaseComp<TableChildrenType>
             {loadingPropertyView(comp.children)}
           </Section>
 
+          <Section name={"Summary"}>
+            {comp.children.showSummary.propertyView({
+              label: trans("table.showSummary")
+            })}
+            {comp.children.summaryRows.propertyView({
+              label: trans("table.totalSummaryRows"),
+              radioButton: true,
+            })}
+          </Section>
+
           <Section name={trans("prop.toolbar")}>
             {comp.children.toolbar.getPropertyView()}
           </Section>
@@ -494,6 +550,9 @@ export function compTablePropertyView<T extends MultiBaseComp<TableChildrenType>
         <>
           <Section name={sectionNames.advanced}>
             {comp.children.expansion.getPropertyView()}
+            {comp.children.inlineAddNewRow.propertyView({
+              label: trans("table.inlineAddNewRow")
+            })}
             {comp.children.showDataLoadSpinner.propertyView({
               label: trans("table.showDataLoadSpinner"),
             })}
@@ -503,6 +562,10 @@ export function compTablePropertyView<T extends MultiBaseComp<TableChildrenType>
                 label: trans("table.dynamicColumnConfig"),
                 tooltip: trans("table.dynamicColumnConfigDesc"),
             })}
+            {comp.children.editModeClicks.propertyView({
+              label: trans("table.editMode"),
+              radioButton: true,
+            })}
             {comp.children.searchText.propertyView({
               label: trans("table.searchText"),
               tooltip: trans("table.searchTextTooltip"),
@@ -537,6 +600,9 @@ export function compTablePropertyView<T extends MultiBaseComp<TableChildrenType>
           <Section name={"Column Style"}>
             {comp.children.columnsStyle.getPropertyView()}
           </Section>
+          <Section name={"Summary Row Style"}>
+            {comp.children.summaryRowStyle.getPropertyView()}
+          </Section>
         </>
       )}
     </>
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/tableSummaryComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/tableSummaryComp.tsx
new file mode 100644
index 0000000000..be47ae3bca
--- /dev/null
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/tableSummaryComp.tsx
@@ -0,0 +1,237 @@
+import { ThemeDetail } from "api/commonSettingApi";
+import { ColumnComp } from "comps/comps/tableComp/column/tableColumnComp";
+import { TableColumnLinkStyleType, TableColumnStyleType, TableSummaryRowStyleType } from "comps/controls/styleControlConstants";
+import styled from "styled-components";
+import { defaultTheme } from "@lowcoder-ee/constants/themeConstants";
+import Table from "antd/es/table";
+import { ReactNode } from "react";
+import Tooltip from "antd/es/tooltip";
+
+const TableSummaryRow = styled(Table.Summary.Row)<{
+  $istoolbarPositionBelow: boolean;
+}>`
+  td:last-child {
+    border-right: unset !important;
+  }
+
+  ${props => !props.$istoolbarPositionBelow && `
+    &:last-child td {
+      border-bottom: none !important;
+    }
+  `}
+  
+`;
+
+const TableSummarCell = styled(Table.Summary.Cell)<{
+  $style: TableSummaryRowStyleType;
+  $defaultThemeDetail: ThemeDetail;
+  $linkStyle?: TableColumnLinkStyleType;
+  $tableSize?: string;
+  $autoHeight?: boolean;
+}>`
+  background: ${(props) => props.$style.background} !important;
+  border-color: ${(props) => props.$style.border} !important;
+  // border-width: ${(props) => props.$style.borderWidth} !important;
+  // border-style: ${(props) => props.$style.borderStyle} !important;
+  border-radius: ${(props) => props.$style.radius};
+  padding: 0 !important;
+
+  > div {
+    margin: ${(props) => props.$style.margin};
+    color: ${(props) => props.$style.text};
+    font-weight: ${(props) => props.$style.textWeight};
+    font-family: ${(props) => props.$style.fontFamily};
+    overflow: hidden; 
+    ${(props) => props.$tableSize === 'small' && `
+      padding: 1px 8px;
+      font-size: ${props.$defaultThemeDetail.textSize == props.$style.textSize ? '14px !important' : props.$style.textSize + ' !important'};
+      font-style:${props.$style.fontStyle} !important;
+      min-height: 14px;
+      line-height: 20px;
+      ${!props.$autoHeight && `
+        overflow-y: auto;
+        max-height: 28px;
+      `};
+    `};
+    ${(props) => props.$tableSize === 'middle' && `
+      padding: 8px 8px;
+      font-size: ${props.$defaultThemeDetail.textSize == props.$style.textSize ? '16px !important' : props.$style.textSize + ' !important'};
+      font-style:${props.$style.fontStyle} !important;
+      min-height: 24px;
+      line-height: 24px;
+      ${!props.$autoHeight && `
+        overflow-y: auto;
+        max-height: 48px;
+      `};
+    `};
+    ${(props) => props.$tableSize === 'large' && `
+      padding: 16px 16px;
+      font-size: ${props.$defaultThemeDetail.textSize == props.$style.textSize ? '18px !important' : props.$style.textSize + ' !important'};
+      font-style:${props.$style.fontStyle} !important;
+      min-height: 48px;
+      ${!props.$autoHeight && `
+        overflow-y: auto;
+        max-height: 96px;
+      `};
+    `};
+    
+    > .ant-badge > .ant-badge-status-text,
+    > div > .markdown-body {
+      color: ${(props) => props.$style.text};
+    }
+
+    > div > svg g {
+      stroke: ${(props) => props.$style.text};
+    }
+
+    > a,
+    > div  a {
+      color: ${(props) => props.$linkStyle?.text};
+
+      &:hover {
+        color: ${(props) => props.$linkStyle?.hoverText};
+      }
+
+      &:active {
+        color: ${(props) => props.$linkStyle?.activeText}};
+      }
+    }
+  }
+`;
+
+const CellWrapper = ({
+  children,
+  tooltipTitle,
+}: {
+  children: ReactNode,
+  tooltipTitle?: string,
+}) => {
+  if (tooltipTitle) {
+    return (
+      <Tooltip title={tooltipTitle} placement="topLeft">
+        {children}
+      </Tooltip>
+    )
+  }
+  return (
+    <>{children}</>
+  )
+};
+
+function TableSummaryCellView(props: {
+  index: number;
+  key: string;
+  children: any;
+  align?: any;
+  rowStyle: TableSummaryRowStyleType;
+  columnStyle: TableColumnStyleType;
+  linkStyle: TableColumnLinkStyleType;
+  tableSize?: string;
+  autoHeight?: boolean;
+  cellColor: string;
+  cellTooltip: string;
+}) {
+  const {
+    children,
+    rowStyle,
+    columnStyle,
+    tableSize,
+    autoHeight,
+    cellColor,
+    cellTooltip,
+    ...restProps
+  } = props;
+
+  const style = {
+    background: cellColor || columnStyle.background || rowStyle.background,
+    margin: columnStyle.margin || rowStyle.margin,
+    text: columnStyle.text || rowStyle.text,
+    border: columnStyle.border || rowStyle.border,
+    borderWidth: rowStyle.borderWidth,
+    borderStyle: rowStyle.borderStyle,
+    radius: columnStyle.radius || rowStyle.radius,
+    textSize: columnStyle.textSize || rowStyle.textSize,
+    textWeight: rowStyle.textWeight || columnStyle.textWeight,
+    fontFamily: rowStyle.fontFamily || columnStyle.fontFamily,
+    fontStyle: rowStyle.fontStyle || columnStyle.fontStyle,
+  }
+
+  return (
+    <TableSummarCell
+      {...restProps}
+      $style={style}
+      $defaultThemeDetail={defaultTheme}
+      $tableSize={tableSize}
+      $autoHeight={autoHeight}
+    >
+      <CellWrapper tooltipTitle={cellTooltip}>
+        <div>{children}</div>
+      </CellWrapper>
+    </TableSummarCell>
+  );
+}
+
+export function TableSummary(props: {
+  tableSize: string;
+  expandableRows: boolean;
+  summaryRows: number;
+  columns: ColumnComp[];
+  summaryRowStyle: TableSummaryRowStyleType;
+  istoolbarPositionBelow: boolean;
+}) {
+  const {
+    columns,
+    summaryRows,
+    summaryRowStyle,
+    tableSize,
+    expandableRows,
+    istoolbarPositionBelow,
+  } = props;
+  let visibleColumns = columns.filter(col => !col.getView().hide);
+  if (expandableRows) {
+    visibleColumns.unshift(new ColumnComp({}));
+  }
+  
+  if (!visibleColumns.length) return <></>;
+
+  return (
+    <Table.Summary>
+      {Array.from(Array(summaryRows)).map((_, rowIndex) => (
+        <TableSummaryRow key={rowIndex} $istoolbarPositionBelow={istoolbarPositionBelow}>
+          {visibleColumns.map((column, index) => {
+            const summaryColumn = column.children.summaryColumns.getView()[rowIndex].getView();
+            return (
+              <TableSummaryCellView
+                index={index}
+                key={`summary-${rowIndex}-${column.getView().dataIndex}-${index}`}
+                tableSize={tableSize}
+                rowStyle={summaryRowStyle}
+                align={summaryColumn.align}
+                cellColor={summaryColumn.cellColor}
+                cellTooltip={summaryColumn.cellTooltip}
+                columnStyle={{
+                  background: summaryColumn.background,
+                  margin: summaryColumn.margin,
+                  text: summaryColumn.text,
+                  border: summaryColumn.border,
+                  radius: summaryColumn.radius,
+                  textSize: summaryColumn.textSize,
+                  textWeight: summaryColumn.textWeight,
+                  fontStyle:summaryColumn.fontStyle,
+                  fontFamily: summaryColumn.fontFamily,
+                }}
+                linkStyle={{
+                  text: summaryColumn.linkColor,
+                  hoverText: summaryColumn.linkHoverColor,
+                  activeText: summaryColumn.linkActiveColor,
+                }}
+              >
+                {summaryColumn.render({}, '').getView().view({})}
+              </TableSummaryCellView>
+            )
+          })}
+        </TableSummaryRow>
+      ))}
+    </Table.Summary>
+  );
+}
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/tableTypes.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/tableTypes.tsx
index 310939f072..d32d3ff248 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/tableTypes.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/tableTypes.tsx
@@ -13,7 +13,7 @@ import {
 import { dropdownControl } from "comps/controls/dropdownControl";
 import { eventHandlerControl } from "comps/controls/eventHandlerControl";
 import { styleControl } from "comps/controls/styleControl";
-import { TableColumnStyle, TableRowStyle, TableStyle, TableToolbarStyle, TableHeaderStyle } from "comps/controls/styleControlConstants";
+import { TableColumnStyle, TableRowStyle, TableStyle, TableToolbarStyle, TableHeaderStyle, TableSummaryRowStyle } from "comps/controls/styleControlConstants";
 import {
   MultiCompBuilder,
   stateComp,
@@ -31,12 +31,38 @@ import {
   RecordConstructorToView,
 } from "lowcoder-core";
 import { controlItem } from "lowcoder-design";
-import { JSONObject } from "util/jsonTypes";
+import { JSONArray, JSONObject } from "util/jsonTypes";
 import { ExpansionControl } from "./expansionControl";
 import { PaginationControl } from "./paginationControl";
 import { SelectionControl } from "./selectionControl";
 import { AutoHeightControl } from "comps/controls/autoHeightControl";
 
+const editModeClickOptions = [
+  {
+    label: trans("table.singleClick"),
+    value: "single",
+  },
+  {
+    label: trans("table.doubleClick"),
+    value: "double",
+  },
+] as const;
+
+const summarRowsOptions = [
+  {
+    label: "1",
+    value: "1",
+  },
+  {
+    label: "2",
+    value: "2",
+  },
+  {
+    label: "3",
+    value: "3",
+  },
+] as const;
+
 const sizeOptions = [
   {
     label: trans("table.small"),
@@ -200,6 +226,7 @@ const tableChildrenMap = {
   showVerticalScrollbar: BoolControl,
   showHorizontalScrollbar: BoolControl,
   data: withIsLoadingMethod(JSONObjectArrayControl),
+  newData: stateComp<JSONArray>([]),
   showDataLoadSpinner: withDefault(BoolPureControl, true),
   columns: ColumnListComp,
   size: dropdownControl(sizeOptions, "middle"),
@@ -207,8 +234,11 @@ const tableChildrenMap = {
   pagination: PaginationControl,
   sort: valueComp<Array<SortValue>>([]),
   toolbar: TableToolbarComp,
+  showSummary: BoolControl,
+  summaryRows: dropdownControl(summarRowsOptions, "1"),
   style: styleControl(TableStyle, 'style'),
   rowStyle: styleControl(TableRowStyle, 'rowStyle'),
+  summaryRowStyle: styleControl(TableSummaryRowStyle, 'summaryRowStyle'),
   toolbarStyle: styleControl(TableToolbarStyle, 'toolbarStyle'),
   headerStyle: styleControl(TableHeaderStyle, 'headerStyle'),
   searchText: StringControl,
@@ -228,6 +258,8 @@ const tableChildrenMap = {
   dynamicColumnConfig: ArrayStringControl,
   expansion: ExpansionControl,
   selectedCell: stateComp<JSONObject>({}),
+  inlineAddNewRow: BoolControl,
+  editModeClicks: dropdownControl(editModeClickOptions, "single"),
 };
 
 export const TableInitComp = (function () {
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/tableUtils.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/tableUtils.tsx
index e180eb6d36..0e1e89d562 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/tableUtils.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/tableUtils.tsx
@@ -20,6 +20,7 @@ import { ColumnListComp, tableDataRowExample } from "./column/tableColumnListCom
 import { TableColumnLinkStyleType, TableColumnStyleType } from "comps/controls/styleControlConstants";
 import Tooltip from "antd/es/tooltip";
 import InfoCircleOutlined from "@ant-design/icons/InfoCircleOutlined";
+import { EMPTY_ROW_KEY } from "./tableCompView";
 
 export const COLUMN_CHILDREN_KEY = "children";
 export const OB_ROW_ORI_INDEX = "__ob_origin_index";
@@ -294,6 +295,7 @@ export function columnsToAntdFormat(
   dynamicColumn: boolean,
   dynamicColumnConfig: Array<string>,
   columnsAggrData: ColumnsAggrData,
+  editMode: string,
   onTableEvent: (eventName: any) => void,
 ): Array<CustomColumnType<RecordType>> {
   const customColumns = columns.filter(col => col.isCustom).map(col => col.dataIndex);
@@ -381,7 +383,7 @@ export function columnsToAntdFormat(
           )
           .getView()
           .view({
-            editable: column.editable,
+            editable: record[OB_ROW_ORI_INDEX].startsWith(EMPTY_ROW_KEY) || column.editable,
             size,
             candidateTags: tags,
             candidateStatus: status,
@@ -391,6 +393,7 @@ export function columnsToAntdFormat(
               currentRow: row,
               currentIndex: index,
             }),
+            editMode,
             onTableEvent,
           });
       },
diff --git a/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx b/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx
index c82d6aa588..b9a6d37fa2 100644
--- a/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx
+++ b/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx
@@ -1545,7 +1545,6 @@ export const TableColumnStyle = [
   getStaticBackground("#00000000"),
   getStaticBorder(),
   MARGIN,
-
   RADIUS,
   TEXT,
   TEXT_SIZE,
@@ -1556,6 +1555,18 @@ export const TableColumnStyle = [
 
 export const TableColumnLinkStyle = [...LinkTextStyle] as const;
 
+export const TableSummaryRowStyle = [
+  BORDER_WIDTH,
+  BORDER_STYLE,
+  ...BG_STATIC_BORDER_RADIUS,
+  MARGIN,
+  TEXT,
+  TEXT_SIZE,
+  TEXT_WEIGHT,
+  FONT_FAMILY,
+  FONT_STYLE,
+] as const;
+
 export const FileStyle = [
   // ...getStaticBgBorderRadiusByBg(SURFACE_COLOR),
   getStaticBackground(SURFACE_COLOR),
@@ -2020,6 +2031,7 @@ export type TableColumnStyleType = StyleConfigType<typeof TableColumnStyle>;
 export type TableColumnLinkStyleType = StyleConfigType<
   typeof TableColumnLinkStyle
 >;
+export type TableSummaryRowStyleType = StyleConfigType<typeof TableSummaryRowStyle>;
 export type FileStyleType = StyleConfigType<typeof FileStyle>;
 export type FileViewerStyleType = StyleConfigType<typeof FileViewerStyle>;
 export type IframeStyleType = StyleConfigType<typeof IframeStyle>;
diff --git a/client/packages/lowcoder/src/constants/themeConstants.ts b/client/packages/lowcoder/src/constants/themeConstants.ts
index 7d0b4062ea..455046fcec 100644
--- a/client/packages/lowcoder/src/constants/themeConstants.ts
+++ b/client/packages/lowcoder/src/constants/themeConstants.ts
@@ -71,6 +71,9 @@ const table = {
   },
   columnsStyle: {
     radius: '0px'
+  },
+  summaryRowStyle: {
+    radius: '0px'
   }
 }
 
diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts
index 3c39a4cc5a..7a2f2df4c8 100644
--- a/client/packages/lowcoder/src/i18n/locales/en.ts
+++ b/client/packages/lowcoder/src/i18n/locales/en.ts
@@ -1998,7 +1998,13 @@ export const en = {
     "iconNull": "Icon When Null",
     "allColumn": "All",
     "visibleColumn": "Visible",
-    "emptyColumns": "No Columns Are Currently Visible"
+    "emptyColumns": "No Columns Are Currently Visible",
+    "showSummary": "Show Summary Row",
+    "totalSummaryRows": "Total Rows",
+    "inlineAddNewRow": "Inline Add New Row",
+    "editMode": "Edit Mode",
+    "singleClick": "Single Click",
+    "doubleClick": "Double Click",
   },
 
 
