Repository: olekukonko/tablewriter

Issue:
How to achieve the same behavior as `table.SetAutoMergeCellsByColumnIndex([]int{0})` in v1?
I read your explanation in [#294](https://github.com/olekukonko/tablewriter/issues/294) about the removal of `table.SetAutoMergeCellsByColumnIndex([]int{0})` in favor of better merging capabilities. I noticed that in v1 there are global merge modes like `MergeHierarchical` and `MergeBoth`, which merge multiple columns automatically.

However, I’d like to merge only specific columns — for example, the first column — similar to what
```go
table.SetAutoMergeCellsByColumnIndex([]int{0})
```
did in v0.0.5.

Is there any way to achieve column-specific merging in v1 without enabling merging for all columns?

Thanks @olekukonko  ! 

Discussion:
@olekukonko: Hello @ZRHann, `SetAutoMergeCellsByColumnIndex` works with **specific** columns, but that is not supported now. I will take my time to look at the requirements and see how this can be achieved, and then I will revert.


Solution patch:
diff --git a/MIGRATION.md b/MIGRATION.md
index 650a195..08ab305 100644
--- a/MIGRATION.md
+++ b/MIGRATION.md
@@ -206,51 +206,51 @@ func main() {
 
 The `defaultConfig()` function (`config.go:defaultConfig`) establishes baseline settings for new tables, ensuring predictable behavior unless overridden. Below is a detailed table of default parameters, organized by configuration section, to help you understand the starting point for table behavior and appearance.
 
-| Section       | Parameter                     | Default Value                     | Description                                                                 |
-|---------------|-------------------------------|-----------------------------------|-----------------------------------------------------------------------------|
-| **Header**    | `Alignment.Global`            | `tw.AlignCenter`                  | Centers header text globally unless overridden by `PerColumn`.               |
-| Header        | `Alignment.PerColumn`         | `[]tw.Align{}`                    | Empty; falls back to `Global` unless specified.                             |
-| Header        | `Formatting.AutoFormat`       | `tw.On`                           | Applies title case (e.g., "col_one" → "COL ONE") to header content.          |
-| Header        | `Formatting.AutoWrap`         | `tw.WrapTruncate`                 | Truncates long header text with "…" based on width constraints.              |
-| Header        | `Formatting.MergeMode`        | `tw.MergeNone`                    | Disables cell merging in headers by default.                                |
-| Header        | `Padding.Global`              | `tw.PaddingDefault` (`" "`)       | Adds one space on left and right of header cells.                           |
-| Header        | `Padding.PerColumn`           | `[]tw.Padding{}`                  | Empty; falls back to `Global` unless specified.                             |
-| Header        | `ColMaxWidths.Global`         | `0` (unlimited)                   | No maximum content width for header cells unless set.                       |
-| Header        | `ColMaxWidths.PerColumn`      | `tw.NewMapper[int, int]()`        | Empty map; no per-column content width limits unless specified.             |
-| Header        | `Filter.Global`               | `nil`                             | No global content transformation for header cells.                          |
-| Header        | `Filter.PerColumn`            | `[]func(string) string{}`         | No per-column content transformations unless specified.                     |
-| **Row**       | `Alignment.Global`            | `tw.AlignLeft`                    | Left-aligns row text globally unless overridden by `PerColumn`.             |
-| Row           | `Alignment.PerColumn`         | `[]tw.Align{}`                    | Empty; falls back to `Global`.                                              |
-| Row           | `Formatting.AutoFormat`       | `tw.Off`                          | Disables auto-formatting (e.g., title case) for row content.                |
-| Row           | `Formatting.AutoWrap`         | `tw.WrapNormal`                   | Wraps long row text naturally at word boundaries based on width constraints.|
-| Row           | `Formatting.MergeMode`        | `tw.MergeNone`                    | Disables cell merging in rows by default.                                   |
-| Row           | `Padding.Global`              | `tw.PaddingDefault` (`" "`)       | Adds one space on left and right of row cells.                              |
-| Row           | `Padding.PerColumn`           | `[]tw.Padding{}`                  | Empty; falls back to `Global`.                                              |
-| Row           | `ColMaxWidths.Global`         | `0` (unlimited)                   | No maximum content width for row cells.                                     |
-| Row           | `ColMaxWidths.PerColumn`      | `tw.NewMapper[int, int]()`        | Empty map; no per-column content width limits.                              |
-| Row           | `Filter.Global`               | `nil`                             | No global content transformation for row cells.                             |
-| Row           | `Filter.PerColumn`            | `[]func(string) string{}`         | No per-column content transformations.                                      |
-| **Footer**    | `Alignment.Global`            | `tw.AlignRight`                   | Right-aligns footer text globally unless overridden by `PerColumn`.         |
-| Footer        | `Alignment.PerColumn`         | `[]tw.Align{}`                    | Empty; falls back to `Global`.                                              |
-| Footer        | `Formatting.AutoFormat`       | `tw.Off`                          | Disables auto-formatting for footer content.                                |
-| Footer        | `Formatting.AutoWrap`         | `tw.WrapNormal`                   | Wraps long footer text naturally.                                           |
-| Footer        | `Formatting.MergeMode`        | `tw.MergeNone`                    | Disables cell merging in footers.                                           |
-| Footer        | `Padding.Global`              | `tw.PaddingDefault` (`" "`)       | Adds one space on left and right of footer cells.                           |
-| Footer        | `Padding.PerColumn`           | `[]tw.Padding{}`                  | Empty; falls back to `Global`.                                              |
-| Footer        | `ColMaxWidths.Global`         | `0` (unlimited)                   | No maximum content width for footer cells.                                  |
-| Footer        | `ColMaxWidths.PerColumn`      | `tw.NewMapper[int, int]()`        | Empty map; no per-column content width limits.                              |
-| Footer        | `Filter.Global`               | `nil`                             | No global content transformation for footer cells.                          |
-| Footer        | `Filter.PerColumn`            | `[]func(string) string{}`         | No per-column content transformations.                                      |
-| **Global**    | `MaxWidth`                    | `0` (unlimited)                   | No overall table width limit.                                               |
-| Global        | `Behavior.AutoHide`           | `tw.Off`                          | Displays empty columns (ignored in streaming).                              |
-| Global        | `Behavior.TrimSpace`          | `tw.On`                           | Trims leading/trailing spaces from cell content.                            |
-| Global        | `Behavior.Header`             | `tw.Control{Hide: tw.Off}`        | Shows header if content is provided.                                        |
-| Global        | `Behavior.Footer`             | `tw.Control{Hide: tw.Off}`        | Shows footer if content is provided.                                        |
-| Global        | `Behavior.Compact`            | `tw.Compact{Merge: tw.Off}`       | No compact width optimization for merged cells.                             |
-| Global        | `Debug`                       | `false`                           | Disables debug logging.                                                     |
-| Global        | `Stream.Enable`               | `false`                           | Disables streaming mode by default.                                         |
-| Global        | `Widths.Global`               | `0` (unlimited)                   | No fixed column width unless specified.                                     |
-| Global        | `Widths.PerColumn`            | `tw.NewMapper[int, int]()`        | Empty map; no per-column fixed widths unless specified.                     |
+| Section       | Parameter                | Default Value                     | Description                                                                 |
+|---------------|--------------------------|-----------------------------------|-----------------------------------------------------------------------------|
+| **Header**    | `Alignment.Global`       | `tw.AlignCenter`                  | Centers header text globally unless overridden by `PerColumn`.               |
+| Header        | `Alignment.PerColumn`    | `[]tw.Align{}`                    | Empty; falls back to `Global` unless specified.                             |
+| Header        | `Formatting.AutoFormat`  | `tw.On`                           | Applies title case (e.g., "col_one" → "COL ONE") to header content.          |
+| Header        | `Formatting.AutoWrap`    | `tw.WrapTruncate`                 | Truncates long header text with "…" based on width constraints.              |
+| Header        | `Merging.Mode`           | `tw.MergeNone`                    | Disables cell merging in headers by default.                                |
+| Header        | `Padding.Global`         | `tw.PaddingDefault` (`" "`)       | Adds one space on left and right of header cells.                           |
+| Header        | `Padding.PerColumn`      | `[]tw.Padding{}`                  | Empty; falls back to `Global` unless specified.                             |
+| Header        | `ColMaxWidths.Global`    | `0` (unlimited)                   | No maximum content width for header cells unless set.                       |
+| Header        | `ColMaxWidths.PerColumn` | `tw.NewMapper[int, int]()`        | Empty map; no per-column content width limits unless specified.             |
+| Header        | `Filter.Global`          | `nil`                             | No global content transformation for header cells.                          |
+| Header        | `Filter.PerColumn`       | `[]func(string) string{}`         | No per-column content transformations unless specified.                     |
+| **Row**       | `Alignment.Global`       | `tw.AlignLeft`                    | Left-aligns row text globally unless overridden by `PerColumn`.             |
+| Row           | `Alignment.PerColumn`    | `[]tw.Align{}`                    | Empty; falls back to `Global`.                                              |
+| Row           | `Formatting.AutoFormat`  | `tw.Off`                          | Disables auto-formatting (e.g., title case) for row content.                |
+| Row           | `Formatting.AutoWrap`    | `tw.WrapNormal`                   | Wraps long row text naturally at word boundaries based on width constraints.|
+| Row           | `Merging.Mode`           | `tw.MergeNone`                    | Disables cell merging in rows by default.                                   |
+| Row           | `Padding.Global`         | `tw.PaddingDefault` (`" "`)       | Adds one space on left and right of row cells.                              |
+| Row           | `Padding.PerColumn`      | `[]tw.Padding{}`                  | Empty; falls back to `Global`.                                              |
+| Row           | `ColMaxWidths.Global`    | `0` (unlimited)                   | No maximum content width for row cells.                                     |
+| Row           | `ColMaxWidths.PerColumn` | `tw.NewMapper[int, int]()`        | Empty map; no per-column content width limits.                              |
+| Row           | `Filter.Global`          | `nil`                             | No global content transformation for row cells.                             |
+| Row           | `Filter.PerColumn`       | `[]func(string) string{}`         | No per-column content transformations.                                      |
+| **Footer**    | `Alignment.Global`       | `tw.AlignRight`                   | Right-aligns footer text globally unless overridden by `PerColumn`.         |
+| Footer        | `Alignment.PerColumn`    | `[]tw.Align{}`                    | Empty; falls back to `Global`.                                              |
+| Footer        | `Formatting.AutoFormat`  | `tw.Off`                          | Disables auto-formatting for footer content.                                |
+| Footer        | `Formatting.AutoWrap`    | `tw.WrapNormal`                   | Wraps long footer text naturally.                                           |
+| Footer        | `Formatting.MergeMode`   | `tw.MergeNone`                    | Disables cell merging in footers.                                           |
+| Footer        | `Padding.Global`         | `tw.PaddingDefault` (`" "`)       | Adds one space on left and right of footer cells.                           |
+| Footer        | `Padding.PerColumn`      | `[]tw.Padding{}`                  | Empty; falls back to `Global`.                                              |
+| Footer        | `ColMaxWidths.Global`    | `0` (unlimited)                   | No maximum content width for footer cells.                                  |
+| Footer        | `ColMaxWidths.PerColumn` | `tw.NewMapper[int, int]()`        | Empty map; no per-column content width limits.                              |
+| Footer        | `Filter.Global`          | `nil`                             | No global content transformation for footer cells.                          |
+| Footer        | `Filter.PerColumn`       | `[]func(string) string{}`         | No per-column content transformations.                                      |
+| **Global**    | `MaxWidth`               | `0` (unlimited)                   | No overall table width limit.                                               |
+| Global        | `Behavior.AutoHide`      | `tw.Off`                          | Displays empty columns (ignored in streaming).                              |
+| Global        | `Behavior.TrimSpace`     | `tw.On`                           | Trims leading/trailing spaces from cell content.                            |
+| Global        | `Behavior.Header`        | `tw.Control{Hide: tw.Off}`        | Shows header if content is provided.                                        |
+| Global        | `Behavior.Footer`        | `tw.Control{Hide: tw.Off}`        | Shows footer if content is provided.                                        |
+| Global        | `Behavior.Compact`       | `tw.Compact{Merge: tw.Off}`       | No compact width optimization for merged cells.                             |
+| Global        | `Debug`                  | `false`                           | Disables debug logging.                                                     |
+| Global        | `Stream.Enable`          | `false`                           | Disables streaming mode by default.                                         |
+| Global        | `Widths.Global`          | `0` (unlimited)                   | No fixed column width unless specified.                                     |
+| Global        | `Widths.PerColumn`       | `tw.NewMapper[int, int]()`        | Empty map; no per-column fixed widths unless specified.                     |
 
 **Notes**:
 - Defaults can be overridden using any configuration method.
@@ -2210,7 +2210,7 @@ import (
 func main() {
 	// Horizontal Merging (Similar to v0.0.5)
 	tableH := tablewriter.NewTable(os.Stdout,
-		tablewriter.WithConfig(tablewriter.Config{Row: tw.CellConfig{Formatting: tw.CellFormatting{MergeMode: tw.MergeHorizontal}}}),
+		tablewriter.WithConfig(tablewriter.Config{Row: tw.CellConfig{Merging: tw.CellMerging{Mode: tw.MergeHorizontal}}}),
 		tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{Symbols: tw.NewSymbols(tw.StyleASCII)})), // Specify renderer for symbols
 	)
 	tableH.Header("Category", "Item", "Item", "Notes") // Note: Two "Item" headers for demo
@@ -2219,7 +2219,7 @@ func main() {
 
 	// Vertical Merging
 	tableV := tablewriter.NewTable(os.Stdout,
-		tablewriter.WithConfig(tablewriter.Config{Row: tw.CellConfig{Formatting: tw.CellFormatting{MergeMode: tw.MergeVertical}}}),
+		tablewriter.WithConfig(tablewriter.Config{Row: tw.CellConfig{Merging: tw.CellMerging{Mode: tw.MergeVertical}}}),
 		tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{Symbols: tw.NewSymbols(tw.StyleASCII)})),
 	)
 	tableV.Header("User", "Permission")
@@ -2230,7 +2230,7 @@ func main() {
 
 	// Hierarchical Merging
 	tableHier := tablewriter.NewTable(os.Stdout,
-		tablewriter.WithConfig(tablewriter.Config{Row: tw.CellConfig{Formatting: tw.CellFormatting{MergeMode: tw.MergeHierarchical}}}),
+		tablewriter.WithConfig(tablewriter.Config{Row: tw.CellConfig{Merging: tw.CellMerging{Mode: tw.MergeHierarchical}}}),
 		tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{Symbols: tw.NewSymbols(tw.StyleASCII)})),
 	)
 	tableHier.Header("Group", "SubGroup", "Item")
diff --git a/README.md b/README.md
index 16d2882..dd9c30a 100644
--- a/README.md
+++ b/README.md
@@ -520,7 +520,7 @@ func main() {
 		tablewriter.WithConfig(tablewriter.Config{
 			Header: tw.CellConfig{Alignment: tw.CellAlignment{Global: tw.AlignCenter}},
 			Row: tw.CellConfig{
-				Formatting: tw.CellFormatting{MergeMode: tw.MergeHierarchical},
+				Merging: tw.CellMerging{Mode: tw.MergeHierarchical},
 				Alignment:  tw.CellAlignment{Global: tw.AlignLeft},
 			},
 		}),
@@ -579,8 +579,8 @@ func main() {
 		})),
 		tablewriter.WithConfig(tablewriter.Config{
 			Row: tw.CellConfig{
-				Formatting: tw.CellFormatting{MergeMode: tw.MergeBoth},
-				Alignment:  tw.CellAlignment{PerColumn: []tw.Align{tw.Skip, tw.Skip, tw.AlignRight, tw.AlignLeft}},
+				Merging:   tw.CellMerging{Mode: tw.MergeBoth},
+				Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.Skip, tw.Skip, tw.AlignRight, tw.AlignLeft}},
 			},
 
 			Footer: tw.CellConfig{
@@ -806,12 +806,12 @@ func main() {
 		tablewriter.WithRenderer(renderer.NewHTML(htmlCfg)),
 		tablewriter.WithConfig(tablewriter.Config{
 			Header: tw.CellConfig{
-				Formatting: tw.CellFormatting{MergeMode: tw.MergeHorizontal}, // Merge identical header cells
-				Alignment:  tw.CellAlignment{Global: tw.AlignCenter},
+				Merging:   tw.CellMerging{Mode: tw.MergeHorizontal}, // Merge identical header cells
+				Alignment: tw.CellAlignment{Global: tw.AlignCenter},
 			},
 			Row: tw.CellConfig{
-				Formatting: tw.CellFormatting{MergeMode: tw.MergeHorizontal}, // Merge identical row cells
-				Alignment:  tw.CellAlignment{Global: tw.AlignLeft},
+				Merging:   tw.CellMerging{Mode: tw.MergeHorizontal}, // Merge identical row cells
+				Alignment: tw.CellAlignment{Global: tw.AlignLeft},
 			},
 			Footer: tw.CellConfig{Alignment: tw.CellAlignment{Global: tw.AlignRight}},
 		}),
diff --git a/_example/symbols/main.go b/_example/symbols/main.go
index 7268132..9f6dc66 100644
--- a/_example/symbols/main.go
+++ b/_example/symbols/main.go
@@ -21,13 +21,11 @@ func main() {
 
 	cnf := tablewriter.Config{
 		Header: tw.CellConfig{
-			Formatting: tw.CellFormatting{Alignment: tw.AlignCenter},
+			Alignment: tw.CellAlignment{Global: tw.AlignCenter},
 		},
 		Row: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHierarchical,
-				Alignment: tw.AlignLeft,
-			},
+			Merging:   tw.CellMerging{Mode: tw.MergeHierarchical},
+			Alignment: tw.CellAlignment{Global: tw.AlignLeft},
 		},
 		Debug: false,
 	}
diff --git a/config.go b/config.go
index ddad9bd..415c957 100644
--- a/config.go
+++ b/config.go
@@ -135,12 +135,12 @@ func (b *ConfigBuilder) WithFooterMaxWidth(maxWidth int) *ConfigBuilder {
 	return b
 }
 
-// WithFooterMergeMode sets the merge behavior for footer cells (e.g., horizontal, hierarchical).
-// Invalid merge modes are ignored.
+// Deprecated: Use .Footer().CellMerging().WithMode(...) instead. This method will be removed in a future version.
 func (b *ConfigBuilder) WithFooterMergeMode(mergeMode int) *ConfigBuilder {
 	if mergeMode < tw.MergeNone || mergeMode > tw.MergeHierarchical {
 		return b
 	}
+	b.config.Footer.Merging.Mode = mergeMode
 	b.config.Footer.Formatting.MergeMode = mergeMode
 	return b
 }
@@ -187,12 +187,12 @@ func (b *ConfigBuilder) WithHeaderMaxWidth(maxWidth int) *ConfigBuilder {
 	return b
 }
 
-// WithHeaderMergeMode sets the merge behavior for header cells (e.g., horizontal, vertical).
-// Invalid merge modes are ignored.
+// Deprecated: Use .Header().CellMerging().WithMode(...) instead. This method will be removed in a future version.
 func (b *ConfigBuilder) WithHeaderMergeMode(mergeMode int) *ConfigBuilder {
 	if mergeMode < tw.MergeNone || mergeMode > tw.MergeHierarchical {
 		return b
 	}
+	b.config.Header.Merging.Mode = mergeMode
 	b.config.Header.Formatting.MergeMode = mergeMode
 	return b
 }
@@ -246,12 +246,12 @@ func (b *ConfigBuilder) WithRowMaxWidth(maxWidth int) *ConfigBuilder {
 	return b
 }
 
-// WithRowMergeMode sets the merge behavior for row cells (e.g., horizontal, hierarchical).
-// Invalid merge modes are ignored.
+// Deprecated: Use .Row().CellMerging().WithMode(...) instead. This method will be removed in a future version.
 func (b *ConfigBuilder) WithRowMergeMode(mergeMode int) *ConfigBuilder {
 	if mergeMode < tw.MergeNone || mergeMode > tw.MergeHierarchical {
 		return b
 	}
+	b.config.Row.Merging.Mode = mergeMode
 	b.config.Row.Formatting.MergeMode = mergeMode
 	return b
 }
@@ -285,6 +285,14 @@ func (h *HeaderConfigBuilder) Formatting() *HeaderFormattingBuilder {
 	}
 }
 
+// Merging returns a HeaderMergingBuilder for configuring cell merging.
+func (h *HeaderConfigBuilder) Merging() *HeaderMergingBuilder {
+	return &HeaderMergingBuilder{
+		parent: h,
+		config: &h.config.Merging,
+	}
+}
+
 // Padding returns a HeaderPaddingBuilder for header padding
 func (h *HeaderConfigBuilder) Padding() *HeaderPaddingBuilder {
 	return &HeaderPaddingBuilder{
@@ -341,6 +349,14 @@ func (r *RowConfigBuilder) Formatting() *RowFormattingBuilder {
 	}
 }
 
+// Merging returns a RowMergingBuilder for configuring cell merging.
+func (r *RowConfigBuilder) Merging() *RowMergingBuilder {
+	return &RowMergingBuilder{
+		parent: r,
+		config: &r.config.Merging,
+	}
+}
+
 // Padding returns a RowPaddingBuilder for row padding
 func (r *RowConfigBuilder) Padding() *RowPaddingBuilder {
 	return &RowPaddingBuilder{
@@ -397,6 +413,14 @@ func (f *FooterConfigBuilder) Formatting() *FooterFormattingBuilder {
 	}
 }
 
+// Merging returns a FooterMergingBuilder for configuring cell merging.
+func (f *FooterConfigBuilder) Merging() *FooterMergingBuilder {
+	return &FooterMergingBuilder{
+		parent: f,
+		config: &f.config.Merging,
+	}
+}
+
 // Padding returns a FooterPaddingBuilder for footer padding
 func (f *FooterConfigBuilder) Padding() *FooterPaddingBuilder {
 	return &FooterPaddingBuilder{
@@ -478,9 +502,10 @@ func (hf *HeaderFormattingBuilder) WithAutoWrap(autoWrap int) *HeaderFormattingB
 	return hf
 }
 
-// WithMergeMode sets merge mode
+// Deprecated: Use .CellMerging().WithMode(...) instead. This method will be removed in a future version.
 func (hf *HeaderFormattingBuilder) WithMergeMode(mergeMode int) *HeaderFormattingBuilder {
 	if mergeMode >= tw.MergeNone && mergeMode <= tw.MergeHierarchical {
+		hf.parent.config.Merging.Mode = mergeMode
 		hf.config.MergeMode = mergeMode
 	}
 	return hf
@@ -512,9 +537,10 @@ func (rf *RowFormattingBuilder) WithAutoWrap(autoWrap int) *RowFormattingBuilder
 	return rf
 }
 
-// WithMergeMode sets merge mode
+// Deprecated: Use .CellMerging().WithMode(...) instead. This method will be removed in a future version.
 func (rf *RowFormattingBuilder) WithMergeMode(mergeMode int) *RowFormattingBuilder {
 	if mergeMode >= tw.MergeNone && mergeMode <= tw.MergeHierarchical {
+		rf.parent.config.Merging.Mode = mergeMode
 		rf.config.MergeMode = mergeMode
 	}
 	return rf
@@ -546,14 +572,117 @@ func (ff *FooterFormattingBuilder) WithAutoWrap(autoWrap int) *FooterFormattingB
 	return ff
 }
 
-// WithMergeMode sets merge mode
+// Deprecated: Use .CellMerging().WithMode(...) instead. This method will be removed in a future version.
 func (ff *FooterFormattingBuilder) WithMergeMode(mergeMode int) *FooterFormattingBuilder {
 	if mergeMode >= tw.MergeNone && mergeMode <= tw.MergeHierarchical {
+		ff.parent.config.Merging.Mode = mergeMode
 		ff.config.MergeMode = mergeMode
 	}
 	return ff
 }
 
+// HeaderMergingBuilder configures header cell merging
+type HeaderMergingBuilder struct {
+	parent *HeaderConfigBuilder
+	config *tw.CellMerging
+}
+
+// Build returns the parent HeaderConfigBuilder.
+func (hm *HeaderMergingBuilder) Build() *HeaderConfigBuilder {
+	return hm.parent
+}
+
+// WithMode sets the merge mode (e.g., tw.MergeHorizontal).
+func (hm *HeaderMergingBuilder) WithMode(mode int) *HeaderMergingBuilder {
+	hm.config.Mode = mode
+	// Also set the deprecated field for backward compatibility
+	hm.parent.config.Formatting.MergeMode = mode
+	return hm
+}
+
+// ByColumnIndex sets specific columns to be merged by their index.
+// If not called, merging applies to all columns.
+func (hm *HeaderMergingBuilder) ByColumnIndex(indices []int) *HeaderMergingBuilder {
+	if len(indices) == 0 {
+		hm.config.ByColumnIndex = nil // nil means apply to all
+	} else {
+		mapper := tw.NewMapper[int, bool]()
+		for _, idx := range indices {
+			mapper.Set(idx, true)
+		}
+		hm.config.ByColumnIndex = mapper
+	}
+	return hm
+}
+
+// RowMergingBuilder configures row cell merging
+type RowMergingBuilder struct {
+	parent *RowConfigBuilder
+	config *tw.CellMerging
+}
+
+// Build returns the parent RowConfigBuilder.
+func (rm *RowMergingBuilder) Build() *RowConfigBuilder {
+	return rm.parent
+}
+
+// WithMode sets the merge mode (e.g., tw.MergeVertical, tw.MergeHierarchical).
+func (rm *RowMergingBuilder) WithMode(mode int) *RowMergingBuilder {
+	rm.config.Mode = mode
+	// Also set the deprecated field for backward compatibility
+	rm.parent.config.Formatting.MergeMode = mode
+	return rm
+}
+
+// ByColumnIndex sets specific columns to be merged by their index.
+// If not called, merging applies to all columns.
+func (rm *RowMergingBuilder) ByColumnIndex(indices []int) *RowMergingBuilder {
+	if len(indices) == 0 {
+		rm.config.ByColumnIndex = nil // nil means apply to all
+	} else {
+		mapper := tw.NewMapper[int, bool]()
+		for _, idx := range indices {
+			mapper.Set(idx, true)
+		}
+		rm.config.ByColumnIndex = mapper
+	}
+	return rm
+}
+
+// FooterMergingBuilder configures footer cell merging
+type FooterMergingBuilder struct {
+	parent *FooterConfigBuilder
+	config *tw.CellMerging
+}
+
+// Build returns the parent FooterConfigBuilder.
+func (fm *FooterMergingBuilder) Build() *FooterConfigBuilder {
+	return fm.parent
+}
+
+// WithMode sets the merge mode (e.g., tw.MergeHorizontal).
+func (fm *FooterMergingBuilder) WithMode(mode int) *FooterMergingBuilder {
+	fm.config.Mode = mode
+	// Also set the deprecated field for backward compatibility
+	fm.parent.config.Formatting.MergeMode = mode
+	return fm
+}
+
+// ByColumnIndex sets specific columns to be merged by their index.
+// If not called, merging applies to all columns.
+func (fm *FooterMergingBuilder) ByColumnIndex(indices []int) *FooterMergingBuilder {
+	if len(indices) == 0 {
+		fm.config.ByColumnIndex = nil // nil means apply to all
+	} else {
+		mapper := tw.NewMapper[int, bool]()
+		for _, idx := range indices {
+			mapper.Set(idx, true)
+		}
+		fm.config.ByColumnIndex = mapper
+	}
+	return fm
+}
+
 // HeaderPaddingBuilder configures header padding
 type HeaderPaddingBuilder struct {
 	parent  *HeaderConfigBuilder
diff --git a/go.mod b/go.mod
index 2d4ca74..6e03ce1 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ require (
 	github.com/fatih/color v1.15.0
 	github.com/mattn/go-runewidth v0.0.19
 	github.com/olekukonko/errors v1.1.0
-	github.com/olekukonko/ll v0.1.1
+	github.com/olekukonko/ll v0.1.2
 	github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0
 )
 
diff --git a/go.sum b/go.sum
index f22267b..ec65b09 100644
--- a/go.sum
+++ b/go.sum
@@ -15,6 +15,8 @@ github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5
 github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
 github.com/olekukonko/ll v0.1.1 h1:9Dfeed5/Mgaxb9lHRAftLK9pVfYETvHn+If6lywVhJc=
 github.com/olekukonko/ll v0.1.1/go.mod h1:2dJo+hYZcJMLMbKwHEWvxCUbAOLc/CXWS9noET22Mdo=
+github.com/olekukonko/ll v0.1.2 h1:lkg/k/9mlsy0SxO5aC+WEpbdT5K83ddnNhAepz7TQc0=
+github.com/olekukonko/ll v0.1.2/go.mod h1:b52bVQRRPObe+yyBl0TxNfhesL0nedD4Cht0/zx55Ew=
 github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 h1:LiZB1h0GIcudcDci2bxbqI6DXV8bF8POAnArqvRrIyw=
 github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0/go.mod h1:F/7q8/HZz+TXjlsoZQQKVYvXTZaFH4QRa3y+j1p7MS0=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
diff --git a/option.go b/option.go
index 2c1f3a2..8902115 100644
--- a/option.go
+++ b/option.go
@@ -122,13 +122,14 @@ func WithFooterAlignmentConfig(alignment tw.CellAlignment) Option {
 	}
 }
 
-// WithFooterMergeMode sets the merge mode for footer cells.
-// Invalid merge modes are ignored, and the change is logged if debugging is enabled.
+// Deprecated: Use a ConfigBuilder with .Footer().CellMerging().WithMode(...) instead.
+// This option will be removed in a future version.
 func WithFooterMergeMode(mergeMode int) Option {
 	return func(target *Table) {
 		if mergeMode < tw.MergeNone || mergeMode > tw.MergeHierarchical {
 			return
 		}
+		target.config.Footer.Merging.Mode = mergeMode
 		target.config.Footer.Formatting.MergeMode = mergeMode
 		if target.logger != nil {
 			target.logger.Debugf("Option: WithFooterMergeMode applied to Table: %v", mergeMode)
@@ -232,13 +233,14 @@ func WithHeaderAutoWrap(wrap int) Option {
 	}
 }
 
-// WithHeaderMergeMode sets the merge mode for header cells.
-// Invalid merge modes are ignored, and the change is logged if debugging is enabled.
+// Deprecated: Use a ConfigBuilder with .Header().CellMerging().WithMode(...) instead.
+// This option will be removed in a future version.
 func WithHeaderMergeMode(mergeMode int) Option {
 	return func(target *Table) {
 		if mergeMode < tw.MergeNone || mergeMode > tw.MergeHierarchical {
 			return
 		}
+		target.config.Header.Merging.Mode = mergeMode
 		target.config.Header.Formatting.MergeMode = mergeMode
 		if target.logger != nil {
 			target.logger.Debugf("Option: WithHeaderMergeMode applied to Table: %v", mergeMode)
@@ -321,13 +323,14 @@ func WithRowAutoWrap(wrap int) Option {
 	}
 }
 
-// WithRowMergeMode sets the merge mode for row cells.
-// Invalid merge modes are ignored, and the change is logged if debugging is enabled.
+// Deprecated: Use a ConfigBuilder with .Row().CellMerging().WithMode(...) instead.
+// This option will be removed in a future version.
 func WithRowMergeMode(mergeMode int) Option {
 	return func(target *Table) {
 		if mergeMode < tw.MergeNone || mergeMode > tw.MergeHierarchical {
 			return
 		}
+		target.config.Row.Merging.Mode = mergeMode
 		target.config.Row.Formatting.MergeMode = mergeMode
 		if target.logger != nil {
 			target.logger.Debugf("Option: WithRowMergeMode applied to Table: %v", mergeMode)
@@ -706,6 +709,9 @@ func defaultConfig() Config {
 				AutoFormat: tw.On,
 				MergeMode:  tw.MergeNone,
 			},
+			Merging: tw.CellMerging{
+				Mode: tw.MergeNone,
+			},
 			Padding: tw.CellPadding{
 				Global: tw.PaddingDefault,
 			},
@@ -720,6 +726,9 @@ func defaultConfig() Config {
 				AutoFormat: tw.Off,
 				MergeMode:  tw.MergeNone,
 			},
+			Merging: tw.CellMerging{
+				Mode: tw.MergeNone,
+			},
 			Padding: tw.CellPadding{
 				Global: tw.PaddingDefault,
 			},
@@ -734,6 +743,9 @@ func defaultConfig() Config {
 				AutoFormat: tw.Off,
 				MergeMode:  tw.MergeNone,
 			},
+			Merging: tw.CellMerging{
+				Mode: tw.MergeNone,
+			},
 			Padding: tw.CellPadding{
 				Global: tw.PaddingDefault,
 			},
@@ -772,10 +784,20 @@ func mergeCellConfig(dst, src tw.CellConfig) tw.CellConfig {
 	if src.ColMaxWidths.Global != 0 {
 		dst.ColMaxWidths.Global = src.ColMaxWidths.Global
 	}
-	if src.Formatting.MergeMode != 0 {
+
+	// Handle merging of the new CellMerging struct and the deprecated MergeMode
+	if src.Merging.Mode != 0 {
+		dst.Merging.Mode = src.Merging.Mode
+		dst.Formatting.MergeMode = src.Merging.Mode
+	} else if src.Formatting.MergeMode != 0 {
+		dst.Merging.Mode = src.Formatting.MergeMode
 		dst.Formatting.MergeMode = src.Formatting.MergeMode
 	}
 
+	if src.Merging.ByColumnIndex != nil {
+		dst.Merging.ByColumnIndex = src.Merging.ByColumnIndex.Clone()
+	}
+
 	dst.Formatting.AutoFormat = src.Formatting.AutoFormat
 
 	if src.Padding.Global.Paddable() {
diff --git a/tablewriter.go b/tablewriter.go
index e1be20e..52fe052 100644
--- a/tablewriter.go
+++ b/tablewriter.go
@@ -1108,7 +1108,7 @@ func (t *Table) prepareContexts() (*renderContext, *mergeContext, error) {
 	}
 	ctx.rowLines = processedRowLinesWithMerges
 
-	t.applyHorizontalMergeWidths(tw.Header, ctx, mctx.headerMerges)
+	t.applyHorizontalMerges(tw.Header, ctx, mctx.headerMerges)
 
 	if t.config.Row.Formatting.MergeMode&tw.MergeVertical != 0 {
 		t.applyVerticalMerges(ctx, mctx)
@@ -1170,7 +1170,7 @@ func (t *Table) prepareFooter(ctx *renderContext, mctx *mergeContext) {
 	mctx.footerMerges = mergeStates
 	ctx.footerLines = t.footers
 	t.logger.Debugf("Base footer widths (normalized from rows/header): %v", ctx.widths[tw.Footer])
-	t.applyHorizontalMergeWidths(tw.Footer, ctx, mctx.footerMerges)
+	t.applyHorizontalMerges(tw.Footer, ctx, mctx.footerMerges)
 	ctx.footerPrepared = true
 	t.logger.Debugf("Footer preparation completed. Final footer widths: %v", ctx.widths[tw.Footer])
 }
diff --git a/tw/cell.go b/tw/cell.go
index 47f0962..19f6775 100644
--- a/tw/cell.go
+++ b/tw/cell.go
@@ -2,16 +2,31 @@ package tw
 
 // CellFormatting holds formatting options for table cells.
 type CellFormatting struct {
-	AutoWrap  int // Wrapping behavior (e.g., WrapTruncate, WrapNormal)
-	MergeMode int // Bitmask for merge behavior (e.g., MergeHorizontal, MergeVertical)
-
-	// Changed form bool to State
-	// See https://github.com/olekukonko/tablewriter/issues/261
+	AutoWrap   int   // Wrapping behavior (e.g., WrapTruncate, WrapNormal)
 	AutoFormat State // Enables automatic formatting (e.g., title case for headers)
 
-	// Deprecated: kept for compatibility
-	// will be removed soon
-	Alignment Align // Text alignment within the cell (e.g., Left, Right, Center)
+	// Deprecated: Kept for backward compatibility. Use CellConfig.CellMerging.Mode instead.
+	// This will be removed in a future version.
+	MergeMode int
+
+	// Deprecated: Kept for backward compatibility. Use CellConfig.Alignment instead.
+	// This will be removed in a future version.
+	Alignment Align
+}
+
+// CellMerging holds the configuration for how cells should be merged.
+// This new struct replaces the deprecated MergeMode.
+type CellMerging struct {
+	// Mode is a bitmask specifying the type of merge (e.g., MergeHorizontal, MergeVertical).
+	Mode int
+
+	// ByColumnIndex specifies which column indices should be considered for merging.
+	// If the mapper is nil or empty, merging applies to all columns (if Mode is set).
+	// Otherwise, only columns with an index present as a key will be merged.
+	ByColumnIndex Mapper[int, bool]
+
+	// ByRowIndex is reserved for future features to specify merging on specific rows.
+	ByRowIndex Mapper[int, bool]
 }
 
 // CellPadding defines padding settings for table cells.
@@ -47,6 +62,7 @@ type CellConfig struct {
 	Filter       CellFilter     // Function to filter cell content (renamed from Filter Filter)
 	Alignment    CellAlignment  // Alignment configuration for cells
 	ColMaxWidths CellWidth      // Per-column maximum width overrides
+	Merging      CellMerging    // Merging holds all configuration related to cell merging.
 
 	// Deprecated: use Alignment.PerColumn instead. Will be removed in a future version.
 	// will be removed soon
diff --git a/tw/mapper.go b/tw/mapper.go
index 058d358..1eee9eb 100644
--- a/tw/mapper.go
+++ b/tw/mapper.go
@@ -210,3 +210,36 @@ func (m Mapper[K, V]) SortedKeys() []K {
 
 	return keys
 }
+
+func NewBoolMapper[K comparable](keys ...K) Mapper[K, bool] {
+	if len(keys) == 0 {
+		return nil
+	}
+	mapper := NewMapper[K, bool]()
+	for _, key := range keys {
+		mapper.Set(key, true)
+	}
+	return mapper
+}
+
+func NewIntMapper[K comparable](keys ...K) Mapper[K, int] {
+	if len(keys) == 0 {
+		return nil
+	}
+	mapper := NewMapper[K, int]()
+	for _, key := range keys {
+		mapper.Set(key, 0)
+	}
+	return mapper
+}
+
+func NewIdentityMapper[K comparable](keys ...K) Mapper[K, K] {
+	if len(keys) == 0 {
+		return nil
+	}
+	mapper := NewMapper[K, K]()
+	for _, key := range keys {
+		mapper.Set(key, key)
+	}
+	return mapper
+}
diff --git a/zoo.go b/zoo.go
index 6e7feb1..7ba5ad0 100644
--- a/zoo.go
+++ b/zoo.go
@@ -18,7 +18,23 @@ import (
 // Parameters ctx and mctx hold rendering and merge state.
 // No return value.
 func (t *Table) applyHierarchicalMerges(ctx *renderContext, mctx *mergeContext) {
-	ctx.logger.Debug("Applying hierarchical merges (left-to-right vertical flow - snapshot comparison)")
+	// First, ensure we should even run this logic.
+	// Check both the new CellMerging struct and the deprecated Formatting field.
+	mergeMode := t.config.Row.Merging.Mode
+	if mergeMode == 0 {
+		mergeMode = t.config.Row.Formatting.MergeMode
+	}
+	if !(mergeMode&tw.MergeHierarchical != 0) {
+		return
+	}
+
+	mergeColumnMapper := t.config.Row.Merging.ByColumnIndex
+	if mergeColumnMapper != nil {
+		ctx.logger.Debugf("Applying hierarchical merges ONLY to specified columns: %v", mergeColumnMapper.Keys())
+	} else {
+		ctx.logger.Debug("Applying hierarchical merges (left-to-right vertical flow - snapshot comparison)")
+	}
+
 	if len(ctx.rowLines) <= 1 {
 		ctx.logger.Debug("Skipping hierarchical merges - less than 2 rows")
 		return
@@ -41,6 +57,12 @@ func (t *Table) applyHierarchicalMerges(ctx *renderContext, mctx *mergeContext)
 		leftCellContinuedHierarchical := false
 
 		for c := 0; c < numCols; c++ {
+			// If a column map is specified, skip columns that are not in it.
+			if mergeColumnMapper != nil && !mergeColumnMapper.Has(c) {
+				leftCellContinuedHierarchical = false // Reset hierarchy tracking
+				continue
+			}
+
 			if mctx.rowMerges[r] == nil {
 				mctx.rowMerges[r] = make(map[int]tw.MergeState)
 			}
@@ -146,15 +168,15 @@ func (t *Table) applyHierarchicalMerges(ctx *renderContext, mctx *mergeContext)
 	ctx.logger.Debug("Hierarchical merge processing completed")
 }
 
-// applyHorizontalMergeWidths adjusts column widths for horizontal merges.
+// applyHorizontalMerges adjusts column widths for horizontal merges.
 // Parameters include position, ctx for rendering, and mergeStates for merges.
 // No return value.
-func (t *Table) applyHorizontalMergeWidths(position tw.Position, ctx *renderContext, mergeStates map[int]tw.MergeState) {
+func (t *Table) applyHorizontalMerges(position tw.Position, ctx *renderContext, mergeStates map[int]tw.MergeState) {
 	if mergeStates == nil {
-		t.logger.Debugf("applyHorizontalMergeWidths: Skipping %s - no merge states", position)
+		t.logger.Debugf("applyHorizontalMerges: Skipping %s - no merge states", position)
 		return
 	}
-	t.logger.Debugf("applyHorizontalMergeWidths: Applying HMerge width recalc for %s", position)
+	t.logger.Debugf("applyHorizontalMerges: Applying HMerge width recalc for %s", position)
 
 	numCols := ctx.numCols
 	targetWidthsMap := ctx.widths[position]
@@ -211,16 +233,31 @@ func (t *Table) applyHorizontalMergeWidths(position tw.Position, ctx *renderCont
 			}
 		}
 	}
-	ctx.logger.Debugf("applyHorizontalMergeWidths: Final widths for %s: %v", position, targetWidthsMap)
+	ctx.logger.Debugf("applyHorizontalMerges: Final widths for %s: %v", position, targetWidthsMap)
 }
 
 // applyVerticalMerges applies vertical merges to row content.
 // Parameters ctx and mctx hold rendering and merge state.
 // No return value.
 func (t *Table) applyVerticalMerges(ctx *renderContext, mctx *mergeContext) {
-	ctx.logger.Debugf("Applying vertical merges across %d rows", len(ctx.rowLines))
-	numCols := ctx.numCols
+	// First, ensure we should even run this logic.
+	// Check both the new CellMerging struct and the deprecated Formatting field.
+	mergeMode := t.config.Row.Merging.Mode
+	if mergeMode == 0 {
+		mergeMode = t.config.Row.Formatting.MergeMode
+	}
+	if !(mergeMode&tw.MergeVertical != 0) {
+		return
+	}
+
+	mergeColumnMapper := t.config.Row.Merging.ByColumnIndex
+	if mergeColumnMapper != nil {
+		ctx.logger.Debugf("Applying vertical merges ONLY to specified columns: %v", mergeColumnMapper.Keys())
+	} else {
+		ctx.logger.Debugf("Applying vertical merges across %d rows", len(ctx.rowLines))
+	}
 
+	numCols := ctx.numCols
 	mergeStartRow := make(map[int]int)
 	mergeStartContent := make(map[int]string)
 
@@ -243,6 +280,11 @@ func (t *Table) applyVerticalMerges(ctx *renderContext, mctx *mergeContext) {
 		currentLineContent := ctx.rowLines[i]
 
 		for col := 0; col < numCols; col++ {
+			// If a column map is specified, skip columns that are not in it.
+			if mergeColumnMapper != nil && !mergeColumnMapper.Has(col) {
+				continue
+			}
+
 			// Join all lines of the cell to compare full content
 			var currentVal strings.Builder
 			for _, line := range currentLineContent {



Test patch:
diff --git a/tablewriter_test.go b/tablewriter_test.go
index 7c12418..b08a959 100644
--- a/tablewriter_test.go
+++ b/tablewriter_test.go
@@ -351,11 +351,11 @@ func TestMergeCellConfig(t *testing.T) {
 			name:       "OverrideMergeModeNone_OnRowDefaultBase",
 			baseConfig: func() tw.CellConfig { return getTestSectionDefaultConfig("row") },
 			inputConfig: tw.CellConfig{
-				Formatting: tw.CellFormatting{MergeMode: tw.MergeNone},
+				Merging: tw.CellMerging{Mode: tw.MergeNone},
 			},
 			expectedConfig: func() tw.CellConfig {
 				cfg := getTestSectionDefaultConfig("row")
-				cfg.Formatting.MergeMode = tw.MergeNone
+				cfg.Merging.Mode = tw.MergeNone
 				cfg.Formatting.AutoFormat = tw.Pending // src.AutoFormat is 0
 				return cfg
 			},
diff --git a/tests/basic_test.go b/tests/basic_test.go
index df415e0..0a17617 100644
--- a/tests/basic_test.go
+++ b/tests/basic_test.go
@@ -760,8 +760,8 @@ func TestAlignmentMigration(t *testing.T) {
 		buf.Reset()
 		table := tablewriter.NewTable(buf)
 		table.Configure(func(cfg *tablewriter.Config) {
-			cfg.Row.Formatting.Alignment = tw.AlignCenter
-			cfg.Row.Formatting.MergeMode = tw.MergeHorizontal
+			cfg.Row.Alignment.Global = tw.AlignCenter
+			cfg.Row.Merging.Mode = tw.MergeHorizontal
 		})
 		table.Header([]string{"DATE", "SECTION A", "SECTION B", "SECTION C", "SECTION D", "SECTION E"})
 		table.Append([]string{"1/1/2014", "apple", "boy", "cat", "dog", "elephant"})
diff --git a/tests/bug_test.go b/tests/bug_test.go
index e21e76d..10275e5 100644
--- a/tests/bug_test.go
+++ b/tests/bug_test.go
@@ -394,13 +394,13 @@ func TestBug271(t *testing.T) {
 	var buf bytes.Buffer
 	table := tablewriter.NewTable(&buf, tablewriter.WithConfig(tablewriter.Config{
 		Header: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHorizontal,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHorizontal,
 			},
 		},
 		Footer: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHorizontal,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHorizontal,
 			},
 			Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.Skip, tw.Skip, tw.AlignRight, tw.AlignLeft}},
 		},
@@ -489,9 +489,11 @@ func TestBug289(t *testing.T) {
 				},
 				Formatting: tw.CellFormatting{
 					AutoWrap:   tw.WrapNone,
-					MergeMode:  tw.MergeNone,
 					AutoFormat: tw.On,
 				},
+				Merging: tw.CellMerging{
+					Mode: tw.MergeNone,
+				},
 				Padding: tw.CellPadding{
 					Global: tw.Padding{
 						Left:      tw.Empty,
diff --git a/tests/colorized_test.go b/tests/colorized_test.go
index ca04663..857c72a 100644
--- a/tests/colorized_test.go
+++ b/tests/colorized_test.go
@@ -148,13 +148,13 @@ func TestColorizedHorizontalMerge(t *testing.T) {
 	var buf bytes.Buffer
 	c := tablewriter.Config{
 		Header: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHorizontal,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHorizontal,
 			},
 		},
 		Row: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHorizontal,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHorizontal,
 			},
 		},
 	}
diff --git a/tests/feature_test.go b/tests/feature_test.go
index 065fa31..0b1f3b2 100644
--- a/tests/feature_test.go
+++ b/tests/feature_test.go
@@ -104,8 +104,10 @@ func TestBatchWidthsWithHorizontalMerge(t *testing.T) {
 		},
 		Row: tw.CellConfig{
 			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHorizontal,
-				AutoWrap:  tw.WrapTruncate,
+				AutoWrap: tw.WrapTruncate,
+			},
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHorizontal,
 			},
 		},
 	}), tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{
@@ -193,7 +195,7 @@ func TestWrapBreakWithConstrainedWidthsNoRightPadding(t *testing.T) {
 func TestCompatMode(t *testing.T) {
 	var buf bytes.Buffer
 	table := tablewriter.NewTable(&buf, tablewriter.WithConfig(tablewriter.Config{
-		Header:   tw.CellConfig{Formatting: tw.CellFormatting{MergeMode: tw.MergeHorizontal}},
+		Header:   tw.CellConfig{Merging: tw.CellMerging{Mode: tw.MergeHorizontal}},
 		Behavior: tw.Behavior{Compact: tw.Compact{Merge: tw.On}},
 		Debug:    true,
 	}))
diff --git a/tests/html_test.go b/tests/html_test.go
index 38560b5..8e96f67 100644
--- a/tests/html_test.go
+++ b/tests/html_test.go
@@ -176,9 +176,9 @@ func TestHTMLHorizontalMerge(t *testing.T) {
 	table := tablewriter.NewTable(&buf,
 		tablewriter.WithRenderer(renderer.NewHTML()),
 		tablewriter.WithConfig(tablewriter.Config{
-			Header: tw.CellConfig{Formatting: tw.CellFormatting{MergeMode: tw.MergeHorizontal}},
-			Row:    tw.CellConfig{Formatting: tw.CellFormatting{MergeMode: tw.MergeHorizontal}},
-			Footer: tw.CellConfig{Formatting: tw.CellFormatting{MergeMode: tw.MergeHorizontal}},
+			Header: tw.CellConfig{Merging: tw.CellMerging{Mode: tw.MergeHorizontal}},
+			Row:    tw.CellConfig{Merging: tw.CellMerging{Mode: tw.MergeHorizontal}},
+			Footer: tw.CellConfig{Merging: tw.CellMerging{Mode: tw.MergeHorizontal}},
 		}),
 	)
 	table.Header([]string{"A", "Merged Header", "Merged Header"})
@@ -211,7 +211,7 @@ func TestHTMLVerticalMerge(t *testing.T) {
 	table := tablewriter.NewTable(&buf,
 		tablewriter.WithRenderer(renderer.NewHTML()),
 		tablewriter.WithConfig(tablewriter.Config{
-			Row: tw.CellConfig{Formatting: tw.CellFormatting{MergeMode: tw.MergeVertical}},
+			Row: tw.CellConfig{Merging: tw.CellMerging{Mode: tw.MergeVertical}},
 		}),
 	)
 	table.Header([]string{"Category", "Item", "Value"})
@@ -248,7 +248,7 @@ func TestHTMLCombinedMerge(t *testing.T) {
 	table := tablewriter.NewTable(&buf,
 		tablewriter.WithRenderer(renderer.NewHTML()),
 		tablewriter.WithConfig(tablewriter.Config{
-			Row: tw.CellConfig{Formatting: tw.CellFormatting{MergeMode: tw.MergeBoth}},
+			Row: tw.CellConfig{Merging: tw.CellMerging{Mode: tw.MergeBoth}},
 		}),
 	)
 	table.Header([]string{"Region", "Quarter", "Sales", "Target"})
@@ -284,7 +284,7 @@ func TestHTMLHierarchicalMerge(t *testing.T) {
 	table := tablewriter.NewTable(&buf,
 		tablewriter.WithRenderer(renderer.NewHTML()),
 		tablewriter.WithConfig(tablewriter.Config{
-			Row: tw.CellConfig{Formatting: tw.CellFormatting{MergeMode: tw.MergeHierarchical}},
+			Row: tw.CellConfig{Merging: tw.CellMerging{Mode: tw.MergeHierarchical}},
 		}),
 		tablewriter.WithHeaderConfig(tw.CellConfig{
 			Formatting: tw.CellFormatting{
diff --git a/tests/markdown_test.go b/tests/markdown_test.go
index 33c8540..655878f 100644
--- a/tests/markdown_test.go
+++ b/tests/markdown_test.go
@@ -201,13 +201,13 @@ func TestMarkdownHorizontalMerge(t *testing.T) {
 	var buf bytes.Buffer
 	c := tablewriter.Config{
 		Header: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHorizontal,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHorizontal,
 			},
 		},
 		Row: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHorizontal,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHorizontal,
 			},
 		},
 	}
diff --git a/tests/merge_test.go b/tests/merge_test.go
index a1e81d1..bea0b0c 100644
--- a/tests/merge_test.go
+++ b/tests/merge_test.go
@@ -13,8 +13,8 @@ func TestVerticalMerge(t *testing.T) {
 	var buf bytes.Buffer
 	table := tablewriter.NewTable(&buf, tablewriter.WithConfig(tablewriter.Config{
 		Row: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeVertical,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeVertical,
 			},
 			Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.Skip, tw.Skip, tw.AlignRight, tw.AlignRight}},
 		},
@@ -53,8 +53,8 @@ func TestHorizontalMerge(t *testing.T) {
 	var buf bytes.Buffer
 	table := tablewriter.NewTable(&buf, tablewriter.WithConfig(tablewriter.Config{
 		Row: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHorizontal,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHorizontal,
 			},
 			Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.AlignCenter, tw.AlignCenter, tw.AlignCenter, tw.AlignCenter}},
 		},
@@ -98,13 +98,13 @@ func TestHorizontalMergeEachLine(t *testing.T) {
 	var buf bytes.Buffer
 	table := tablewriter.NewTable(&buf, tablewriter.WithConfig(tablewriter.Config{
 		Row: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHorizontal,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHorizontal,
 			},
 		},
 		Footer: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHorizontal,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHorizontal,
 			},
 			Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.Skip, tw.Skip, tw.AlignRight, tw.AlignLeft}},
 		},
@@ -150,8 +150,8 @@ func TestHorizontalMergeEachLineCenter(t *testing.T) {
 	var buf bytes.Buffer
 	table := tablewriter.NewTable(&buf, tablewriter.WithConfig(tablewriter.Config{
 		Row: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHorizontal,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHorizontal,
 			},
 			Alignment: tw.CellAlignment{Global: tw.AlignCenter},
 		},
@@ -196,13 +196,13 @@ func TestHorizontalMergeAlignFooter(t *testing.T) {
 	var buf bytes.Buffer
 	table := tablewriter.NewTable(&buf, tablewriter.WithConfig(tablewriter.Config{
 		Row: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHorizontal,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHorizontal,
 			},
 		},
 		Footer: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHorizontal,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHorizontal,
 			},
 			Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.Skip, tw.Skip, tw.AlignRight, tw.AlignLeft}},
 		},
@@ -245,8 +245,8 @@ func TestVerticalMergeLines(t *testing.T) {
 	var buf bytes.Buffer
 	table := tablewriter.NewTable(&buf, tablewriter.WithConfig(tablewriter.Config{
 		Row: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeVertical,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeVertical,
 			},
 			Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.Skip, tw.Skip, tw.AlignRight, tw.AlignRight}},
 		},
@@ -289,13 +289,13 @@ func TestMergeBoth(t *testing.T) {
 
 	c := tablewriter.Config{
 		Row: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeBoth,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeBoth,
 			},
 		},
 		Footer: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHorizontal,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHorizontal,
 			},
 			Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.AlignRight, tw.AlignRight, tw.AlignRight, tw.AlignLeft}},
 		},
@@ -373,8 +373,8 @@ func TestMergeHierarchical(t *testing.T) {
 	var buf bytes.Buffer
 	table := tablewriter.NewTable(&buf, tablewriter.WithConfig(tablewriter.Config{
 		Row: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHierarchical,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHierarchical,
 			},
 		},
 	}),
@@ -417,8 +417,8 @@ func TestMergeHierarchicalUnicode(t *testing.T) {
 	var buf bytes.Buffer
 	table := tablewriter.NewTable(&buf, tablewriter.WithConfig(tablewriter.Config{
 		Row: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHierarchical,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHierarchical,
 			},
 		},
 	}),
@@ -462,8 +462,8 @@ func TestMergeWithPadding(t *testing.T) {
 
 	table := tablewriter.NewTable(&buf, tablewriter.WithConfig(tablewriter.Config{
 		Row: tw.CellConfig{
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeBoth,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeBoth,
 			},
 			Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.Skip, tw.Skip, tw.AlignRight, tw.AlignLeft}},
 		},
@@ -523,8 +523,8 @@ func TestMergeWithMultipleLines(t *testing.T) {
 		buf.Reset()
 		table := tablewriter.NewTable(&buf, tablewriter.WithConfig(tablewriter.Config{
 			Row: tw.CellConfig{
-				Formatting: tw.CellFormatting{
-					MergeMode: tw.MergeHorizontal,
+				Merging: tw.CellMerging{
+					Mode: tw.MergeHorizontal,
 				},
 				Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.AlignLeft, tw.AlignLeft, tw.AlignLeft, tw.AlignLeft}},
 			},
@@ -569,8 +569,8 @@ func TestMergeWithMultipleLines(t *testing.T) {
 		buf.Reset()
 		table := tablewriter.NewTable(&buf, tablewriter.WithConfig(tablewriter.Config{
 			Row: tw.CellConfig{
-				Formatting: tw.CellFormatting{
-					MergeMode: tw.MergeVertical,
+				Merging: tw.CellMerging{
+					Mode: tw.MergeVertical,
 				},
 				Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.AlignLeft, tw.AlignLeft, tw.AlignLeft, tw.AlignLeft}},
 			},
@@ -614,8 +614,8 @@ func TestMergeWithMultipleLines(t *testing.T) {
 		buf.Reset()
 		table := tablewriter.NewTable(&buf, tablewriter.WithConfig(tablewriter.Config{
 			Row: tw.CellConfig{
-				Formatting: tw.CellFormatting{
-					MergeMode: tw.MergeHierarchical,
+				Merging: tw.CellMerging{
+					Mode: tw.MergeHierarchical,
 				},
 				Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.AlignLeft, tw.AlignLeft, tw.AlignLeft, tw.AlignLeft}},
 			},
@@ -660,13 +660,13 @@ func TestMergeHierarchicalCombined(t *testing.T) {
 	table := tablewriter.NewTable(&buf, tablewriter.WithConfig(tablewriter.Config{
 		Header: tw.CellConfig{Alignment: tw.CellAlignment{Global: tw.AlignCenter}},
 		Row: tw.CellConfig{
-			Formatting: tw.CellFormatting{MergeMode: tw.MergeHierarchical},
-			Alignment:  tw.CellAlignment{Global: tw.AlignLeft},
+			Merging:   tw.CellMerging{Mode: tw.MergeHierarchical},
+			Alignment: tw.CellAlignment{Global: tw.AlignLeft},
 		},
 		Footer: tw.CellConfig{
 			Alignment: tw.CellAlignment{Global: tw.AlignLeft},
-			Formatting: tw.CellFormatting{
-				MergeMode: tw.MergeHorizontal,
+			Merging: tw.CellMerging{
+				Mode: tw.MergeHorizontal,
 			},
 		},
 		Debug: true,
@@ -712,3 +712,126 @@ func TestMergeHierarchicalCombined(t *testing.T) {
 		t.Error(table.Debug())
 	}
 }
+
+// TestMergeVerticalByColumnIndex verifies that vertical merging
+// only applies to the columns specified by the new API.
+func TestMergeVerticalByColumnIndex(t *testing.T) {
+	var buf bytes.Buffer
+
+	// Data where columns 0, 1, and 3 have duplicates that could be merged.
+	data := [][]string{
+		{"A", "The Good", "500", "OK"},
+		{"A", "The Bad", "288", "OK"},
+		{"B", "The Ugly", "120", "FAIL"},
+		{"B", "The Ugly", "200", "FAIL"},
+		{"B", "The Ugly", "300", "OK"},
+	}
+
+	// Use the new fluent builder to configure column-specific merging.
+	b := tablewriter.NewConfigBuilder()
+	b.Row().Merging().
+		WithMode(tw.MergeVertical). // Enable Vertical Merging
+		ByColumnIndex([]int{0, 3}). // ONLY apply it to column 0 and 3
+		Build()
+
+	table := tablewriter.NewTable(&buf,
+		tablewriter.WithConfig(b.Build()),
+		tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{
+			Settings: tw.Settings{
+				Separators: tw.Separators{
+					BetweenRows: tw.On,
+				},
+			},
+		})))
+
+	table.Header([]string{"Name", "Sign", "Rating", "Status"})
+	table.Bulk(data)
+	table.Render()
+
+	// EXPECTED:
+	// - Column 0 ("Name") SHOULD be merged.
+	// - Column 1 ("Sign") should NOT be merged, even though "The Ugly" repeats.
+	// - Column 3 ("Status") SHOULD be merged.
+	expected := `
+			┌──────┬──────────┬────────┬────────┐
+			│ NAME │   SIGN   │ RATING │ STATUS │
+			├──────┼──────────┼────────┼────────┤
+			│ A    │ The Good │ 500    │ OK     │
+			│      ├──────────┼────────┤        │
+			│      │ The Bad  │ 288    │        │
+			├──────┼──────────┼────────┼────────┤
+			│ B    │ The Ugly │ 120    │ FAIL   │
+			│      ├──────────┼────────┤        │
+			│      │ The Ugly │ 200    │        │
+			│      ├──────────┼────────┼────────┤
+			│      │ The Ugly │ 300    │ OK     │
+			└──────┴──────────┴────────┴────────┘
+`
+
+	if !visualCheck(t, "MergeVerticalByColumnIndex", buf.String(), expected) {
+		t.Error(table.Debug())
+	}
+}
+
+// TestMergeHierarchicalByColumnIndex verifies that hierarchical merging
+// correctly respects the column index filter.
+func TestMergeHierarchicalByColumnIndex(t *testing.T) {
+	var buf bytes.Buffer
+
+	data := [][]string{
+		{"Engineering", "Backend", "API Team", "Alice"},
+		{"Engineering", "Backend", "Database Team", "Bob"},
+		{"Engineering", "Frontend", "UI Team", "Charlie"},
+		{"Marketing", "Digital", "SEO Team", "Dave"},
+		{"Marketing", "Digital", "Content Team", "Eve"},
+		{"Marketing", "Brand", "PR Team", "Frank"},
+	}
+
+	// Use the new fluent builder to enable hierarchical merging for columns 0 and 1 only.
+	b := tablewriter.NewConfigBuilder()
+	b.Row().Merging().
+		WithMode(tw.MergeHierarchical).
+		ByColumnIndex([]int{0, 1}).
+		Build()
+
+	table := tablewriter.NewTable(&buf,
+		tablewriter.WithConfig(b.Build()),
+		tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{
+			Settings: tw.Settings{
+				Separators: tw.Separators{
+					BetweenRows: tw.On,
+				},
+			},
+		})))
+
+	table.Header([]string{"Department", "Division", "Team", "Lead"})
+	table.Bulk(data)
+	table.Render()
+
+	// EXPECTED:
+	// - Column 0 ("Department") SHOULD merge.
+	// - Column 1 ("Division") SHOULD merge hierarchically (e.g., "Backend" and "Digital").
+	// - Column 2 ("Team") should NOT merge because it's not in the index list.
+	//   This will break the hierarchical chain for column 3.
+	// - Column 3 ("Lead") should NOT merge.
+	expected := `
+		┌─────────────┬──────────┬───────────────┬─────────┐
+		│ DEPARTMENT  │ DIVISION │     TEAM      │  LEAD   │
+		├─────────────┼──────────┼───────────────┼─────────┤
+		│ Engineering │ Backend  │ API Team      │ Alice   │
+		│             │          ├───────────────┼─────────┤
+		│             │          │ Database Team │ Bob     │
+		│             ├──────────┼───────────────┼─────────┤
+		│             │ Frontend │ UI Team       │ Charlie │
+		├─────────────┼──────────┼───────────────┼─────────┤
+		│ Marketing   │ Digital  │ SEO Team      │ Dave    │
+		│             │          ├───────────────┼─────────┤
+		│             │          │ Content Team  │ Eve     │
+		│             ├──────────┼───────────────┼─────────┤
+		│             │ Brand    │ PR Team       │ Frank   │
+		└─────────────┴──────────┴───────────────┴─────────┘
+`
+	if !visualCheck(t, "MergeHierarchicalByColumnIndex", buf.String(), expected) {
+		t.Error(table.Debug())
+	}
+}
diff --git a/tests/svg_test.go b/tests/svg_test.go
index 10e2dc7..a1b68e5 100644
--- a/tests/svg_test.go
+++ b/tests/svg_test.go
@@ -248,7 +248,7 @@ func TestSVGHierarchicalMerge(t *testing.T) {
 		tablewriter.WithRenderer(renderer.NewSVG(svgCfg)),
 		tablewriter.WithConfig(tablewriter.Config{
 			Header: tw.CellConfig{Alignment: tw.CellAlignment{Global: tw.AlignCenter}},
-			Row:    tw.CellConfig{Formatting: tw.CellFormatting{MergeMode: tw.MergeHierarchical}},
+			Row:    tw.CellConfig{Merging: tw.CellMerging{Mode: tw.MergeHierarchical}},
 		}),
 	)
 	table.Header([]string{"L1", "L2", "L3"})
@@ -305,7 +305,7 @@ func TestSVGVerticalMerge(t *testing.T) {
 	table := tablewriter.NewTable(&buf,
 		tablewriter.WithRenderer(renderer.NewSVG(svgCfg)),
 		tablewriter.WithConfig(tablewriter.Config{
-			Row: tw.CellConfig{Formatting: tw.CellFormatting{MergeMode: tw.MergeVertical}},
+			Row: tw.CellConfig{Merging: tw.CellMerging{Mode: tw.MergeVertical}},
 		}),
 	)
 	table.Header([]string{"Cat", "Item"})
@@ -381,10 +381,10 @@ func TestSVGHorizontalMerge(t *testing.T) {
 		tablewriter.WithRenderer(renderer.NewSVG(svgCfg)),
 		tablewriter.WithConfig(tablewriter.Config{
 			Header: tw.CellConfig{
-				Formatting: tw.CellFormatting{MergeMode: tw.MergeHorizontal},
-				Alignment:  tw.CellAlignment{Global: tw.AlignCenter},
+				Merging:   tw.CellMerging{Mode: tw.MergeHorizontal},
+				Alignment: tw.CellAlignment{Global: tw.AlignCenter},
 			},
-			Row: tw.CellConfig{Formatting: tw.CellFormatting{MergeMode: tw.MergeHorizontal}, Alignment: tw.CellAlignment{Global: tw.AlignLeft}},
+			Row: tw.CellConfig{Merging: tw.CellMerging{Mode: tw.MergeHorizontal}, Alignment: tw.CellAlignment{Global: tw.AlignLeft}},
 		}),
 	)
 	table.Header([]string{"A", "Merged Header", "Merged Header"})