# How to Configure Table Features (Merge Cells & Resize Columns) in reactjs-tiptap-editor

> Learn to merge cells and resize columns in reactjs-tiptap-editor. This guide shows how to enable table features and efficiently manage table content with simple code.

- Repository: [Hung Hoang/reactjs-tiptap-editor](https://github.com/hunghg255/reactjs-tiptap-editor)
- Tags: how-to-guide
- Published: 2026-03-03

---

**Enable `resizable: true` in the Table extension options to activate column resizing, and invoke `editor.chain().focus().mergeCells().run()` via the `RichTextBubbleTable` component to merge selected cells.**

The **reactjs-tiptap-editor** repository extends TipTap's `@tiptap/extension-table` with custom React wrappers to provide a comprehensive table editing experience. Configuring table features requires modifying the extension configuration in [`src/extensions/Table/Table.ts`](https://github.com/hunghg255/reactjs-tiptap-editor/blob/main/src/extensions/Table/Table.ts) for resizing capabilities, and leveraging the bubble menu component in [`src/components/Bubble/RichTextBubbleTable.tsx`](https://github.com/hunghg255/reactjs-tiptap-editor/blob/main/src/components/Bubble/RichTextBubbleTable.tsx) for cell merging operations.

## Enabling Column Resizing

### Extension Configuration

Column resizing is controlled through the custom `Table` extension located at [`src/extensions/Table/Table.ts`](https://github.com/hunghg255/reactjs-tiptap-editor/blob/main/src/extensions/Table/Table.ts). The extension overrides the default `addOptions()` method to enable resizing behaviors by default.

```typescript
// src/extensions/Table/Table.ts
addOptions() {
  return {
    ...this.parent?.(),
    resizable: true,          // Enables draggable column borders
    lastColumnResizable: true // Allows resizing the right-most column
  };
}

```

When `resizable` is set to `true`, TipTap injects mouse-draggable handles on each column border. Dragging these handles updates the column widths in the document model immediately.

### Runtime Configuration

You can override these defaults when initializing the editor instance to disable resizing for specific use cases, such as read-only views.

```tsx
import { Table } from '@/extensions/Table/Table';

const editor = new Editor({
  extensions: [
    Table.configure({
      resizable: false,
      lastColumnResizable: false
    }),
    // ...other extensions
  ],
});

```

## Implementing Cell Merging

### RichTextBubbleTable Integration

The merge functionality is exposed through the `RichTextBubbleTable` component in [`src/components/Bubble/RichTextBubbleTable.tsx`](https://github.com/hunghg255/reactjs-tiptap-editor/blob/main/src/components/Bubble/RichTextBubbleTable.tsx). This bubble menu appears when the cursor is inside a table and provides the merge action.

The component calls `onMergeCell` (lines 51-53) which executes the merge command:

```tsx
// src/components/Bubble/RichTextBubbleTable.tsx
function onMergeCell() {
  editor.chain().focus().mergeCells().run();
}

```

The button is conditionally enabled only when `editor?.can()?.mergeCells?.()` returns `true`, ensuring the action only appears for valid rectangular cell selections.

### Programmatic Usage

You can trigger cell merging from any custom UI component using the same chain command:

```tsx
const mergeSelectedCells = () => {
  editor.chain().focus().mergeCells().run();
};

// Example action button with disabled state
<ActionButton
  action={mergeSelectedCells}
  disabled={!editor?.can()?.mergeCells?.()}
  icon='TableCellsMerge'
  tooltip='Merge selected cells'
/>

```

## Complete Implementation Example

Below is a minimal implementation that demonstrates inserting a resizable table and accessing the merge functionality:

```tsx
import React from 'react';
import { ActionButton } from '@/components';
import { Table } from '@/extensions/Table/Table';
import { RichTextBubbleTable } from '@/components/Bubble/RichTextBubbleTable';
import { useEditorInstance } from '@/store/editor';

export const TableEditor = () => {
  const editor = useEditorInstance();

  const insertTable = () => {
    editor
      .chain()
      .focus()
      .insertTable({ rows: 3, cols: 3, withHeaderRow: false })
      .run();
  };

  return (
    <>
      <ActionButton
        action={insertTable}
        icon='Table'
        tooltip='Insert 3×3 resizable table'
      />
      {/* Bubble menu provides merge, split, add/delete row/column actions */}
      <RichTextBubbleTable />
    </>
  );
};

```

This configuration creates tables with draggable column borders (via the `resizable` option) and exposes the merge cells button through the bubble menu when multiple cells are selected.

## Summary

- Configure `resizable: true` in [`src/extensions/Table/Table.ts`](https://github.com/hunghg255/reactjs-tiptap-editor/blob/main/src/extensions/Table/Table.ts) to enable draggable column resize handles on all tables.
- Set `lastColumnResizable: true` to ensure users can resize the right-most column border.
- Invoke `editor.chain().focus().mergeCells().run()` to programmatically merge selected cells into a single cell.
- Use `editor.can().mergeCells()` to conditionally render merge buttons only when a valid rectangular selection exists.
- The `RichTextBubbleTable` component at [`src/components/Bubble/RichTextBubbleTable.tsx`](https://github.com/hunghg255/reactjs-tiptap-editor/blob/main/src/components/Bubble/RichTextBubbleTable.tsx) provides the standard UI for table manipulation actions.

## Frequently Asked Questions

### How do I disable column resizing in reactjs-tiptap-editor?

Configure the `Table` extension with `resizable: false` when initializing the editor. This removes the draggable handles from all column borders.

### Can I trigger cell merging from a custom toolbar instead of the bubble menu?

Yes. Import `useEditorInstance` from your editor store and call `editor.chain().focus().mergeCells().run()` directly from any button or keyboard shortcut handler. Ensure you check `editor.can().mergeCells()` to validate the selection first.

### What determines if the merge cells button is available?

The button availability depends on `editor.can().mergeCells()`, which validates that the current selection forms a proper rectangular range of adjacent table cells. If you select cells that are not contiguous or overlap existing merged cells, the command returns false and the button disables automatically.

### How do I prevent users from resizing only the last column?

Set `lastColumnResizable: false` in the `Table` extension options. This keeps resizing enabled for all other columns while removing the resize handle from the right-most column border.