Skip to main content
This example demonstrates the power of nested tables in Tabulate by creating a UML class diagram. It showcases how tables can be embedded within other tables to create sophisticated visual structures.

Complete Example

#include <tabulate/table.hpp>
using namespace tabulate;
using Row_t = Table::Row_t;

int main() {
  Table class_diagram;

  // Global styling
  class_diagram.format().font_style({FontStyle::bold}).font_align(FontAlign::center).width(60);

  // Animal class
  Table animal;
  animal.add_row(Row_t{"Animal"});
  animal[0].format().font_align(FontAlign::center);

  // Animal properties nested table
  Table animal_properties;
  animal_properties.format().width(20);
  animal_properties.add_row(Row_t{"+age: Int"});
  animal_properties.add_row(Row_t{"+gender: String"});
  animal_properties[1].format().hide_border_top();

  // Animal methods nested table
  Table animal_methods;
  animal_methods.format().width(20);
  animal_methods.add_row(Row_t{"+isMammal()"});
  animal_methods.add_row(Row_t{"+mate()"});
  animal_methods[1].format().hide_border_top();

  animal.add_row(Row_t{animal_properties});
  animal.add_row(Row_t{animal_methods});
  animal[2].format().hide_border_top();

  class_diagram.add_row(Row_t{animal});

  // Add rows in the class diagram for the up-facing arrow
  // Thanks to center alignment, these will align just fine
  class_diagram.add_row(Row_t{"▲"});
  class_diagram[1][0].format().hide_border_top().multi_byte_characters(true);
  class_diagram.add_row(Row_t{"|"});
  class_diagram[2].format().hide_border_top();
  class_diagram.add_row(Row_t{"|"});
  class_diagram[3].format().hide_border_top();

  // Duck class
  Table duck;
  duck.add_row(Row_t{"Duck"});
  duck[0].format().font_align(FontAlign::center);

  // Duck properties nested table
  Table duck_properties;
  duck_properties.format().width(40);
  duck_properties.add_row(Row_t{"+beakColor: String = \"yellow\""});

  // Duck methods nested table
  Table duck_methods;
  duck_methods.format().width(40);
  duck_methods.add_row(Row_t{"+swim()"});
  duck_methods.add_row(Row_t{"+quack()"});
  duck_methods[1].format().hide_border_top();

  duck.add_row(Row_t{duck_properties});
  duck.add_row(Row_t{duck_methods});
  duck[2].format().hide_border_top();

  class_diagram.add_row(Row_t{duck});
  class_diagram[4].format().hide_border_top();

  std::cout << class_diagram << std::endl;
}

Output

The diagram will render like this:
┌────────────────────────────────────────────────────────────┐
│                           Animal                           │
├────────────────────────────────────────────────────────────┤
│ +age: Int                                                  │
│ +gender: String                                            │
├────────────────────────────────────────────────────────────┤
│ +isMammal()                                                │
│ +mate()                                                    │
└────────────────────────────────────────────────────────────┘

                              |
                              |
┌────────────────────────────────────────────────────────────┐
│                            Duck                            │
├────────────────────────────────────────────────────────────┤
│ +beakColor: String = "yellow"                              │
├────────────────────────────────────────────────────────────┤
│ +swim()                                                    │
│ +quack()                                                   │
└────────────────────────────────────────────────────────────┘

Key Concepts

Nested Table Structure

The example creates multiple levels of nesting:
  1. Main container: class_diagram - holds everything
  2. Class boxes: animal and duck tables
  3. Section tables: animal_properties, animal_methods, duck_properties, duck_methods
Table class_diagram;
class_diagram.format()
    .font_style({FontStyle::bold})
    .font_align(FontAlign::center)
    .width(60);

Border Management

To create seamless sections, borders are selectively hidden:
// Hide top border to merge with previous row
animal_properties[1].format().hide_border_top();
animal_methods[1].format().hide_border_top();

// Hide borders between class boxes and arrow
class_diagram[1][0].format().hide_border_top();
class_diagram[2].format().hide_border_top();
class_diagram[3].format().hide_border_top();
class_diagram[4].format().hide_border_top();
Hiding borders between related rows creates visual groupings and cleaner diagrams.

Unicode Characters

The inheritance arrow uses Unicode characters:
class_diagram.add_row(Row_t{"▲"});
class_diagram[1][0].format()
    .hide_border_top()
    .multi_byte_characters(true);  // Important for Unicode!

class_diagram.add_row(Row_t{"|"});
Always set multi_byte_characters(true) when using Unicode symbols to ensure proper width calculation.

Building Blocks

Class Header

Each class starts with a centered header:
Table animal;
animal.add_row(Row_t{"Animal"});
animal[0].format().font_align(FontAlign::center);

Properties Section

Properties are listed in a nested table:
Table animal_properties;
animal_properties.format().width(20);
animal_properties.add_row(Row_t{"+age: Int"});
animal_properties.add_row(Row_t{"+gender: String"});
animal_properties[1].format().hide_border_top();

Methods Section

Methods follow the same pattern:
Table animal_methods;
animal_methods.format().width(20);
animal_methods.add_row(Row_t{"+isMammal()"});
animal_methods.add_row(Row_t{"+mate()"});
animal_methods[1].format().hide_border_top();

Extending the Example

Adding More Classes

You can extend this to show multiple inheritance:
Table mammal;
mammal.add_row(Row_t{"Mammal"});
// ... add properties and methods

Table bird;
bird.add_row(Row_t{"Bird"});
// ... add properties and methods

// Create horizontal layout
Table subclasses;
subclasses.add_row(Row_t{mammal, bird});
class_diagram.add_row(Row_t{subclasses});

Adding Relationships

Show composition or aggregation:
// Composition diamond
class_diagram.add_row(Row_t{"◆─────"});
class_diagram[5][0].format()
    .hide_border_top()
    .multi_byte_characters(true);

Color Coding

Differentiate class types with colors:
// Interface - blue header
animal[0].format()
    .font_color(Color::blue)
    .font_style({FontStyle::bold, FontStyle::italic});

// Abstract class - green header
duck[0].format()
    .font_color(Color::green)
    .font_style({FontStyle::bold});

// Concrete class - default

Use Cases

This nested table technique is perfect for:
  • UML class diagrams
  • Organization charts
  • Flowcharts
  • Network topologies
  • Decision trees
  • Hierarchical data visualization
The key to complex diagrams is breaking them down into smaller table components, then assembling them with careful border management.

Build docs developers (and LLMs) love