FTXUI

A modern C++ library for building TUIs in a functional and declarative style. Component-based design similar to React, header-only with no dependencies.

TUITerminalFunctionalReactiveC++

GitHub Overview

ArthurSonzogni/FTXUI

:computer: C++ Functional Terminal User Interface. :heart:

Stars8,531
Watchers81
Forks490
Created:January 27, 2019
Language:C++
License:MIT License

Topics

arthursonzogniasciiascii-artcppcursesimpleterminalterminal-basedtuiuiuser-interfacexterm

Star History

ArthurSonzogni/FTXUI Star History
Data as of: 7/25/2025, 11:08 AM

FTXUI

FTXUI is a modern C++ library for building Terminal User Interfaces (TUI) in a functional and declarative style. Adopting a React-like component-based design, it features header-only implementation with no external dependencies. It enables efficient development of beautiful and interactive terminal applications.

Features

Functional & Reactive Programming

  • Declarative UI: React-like declarative approach
  • Component-Based: Reusable UI components
  • State Management: Automatic UI updates and event handling
  • Functional Paradigm: Pure functions and immutable data

Architecture

  • screen: Final rendering to terminal
  • dom: Element tree defining UI structure
  • component: Interactive elements and event handling
  • animation: Smooth animation capabilities

Rich Components

  • Input: Input, Checkbox, Radiobox, Slider
  • Selection: Menu, Dropdown, Toggle
  • Layout: Container, Scroller, Collapsible
  • Display: Gauge, Spinner, Table

Modern Features

  • Header-Only: Easy integration, no dependencies
  • C++17 Support: Leverages modern C++ features
  • Unicode Support: Emoji and internationalization support
  • Mouse Support: Click, drag, and wheel events

Basic Usage

Installation

# Using CMake
git clone https://github.com/ArthurSonzogni/FTXUI
mkdir build && cd build
cmake ..
make -j

# Using vcpkg
vcpkg install ftxui

# Compilation example
g++ -std=c++17 main.cpp -lftxui-screen -lftxui-dom -lftxui-component

Hello World

#include <ftxui/dom/elements.hpp>
#include <ftxui/screen/screen.hpp>
#include <iostream>

using namespace ftxui;

int main() {
  // Create DOM elements
  auto document = hbox({
    text("Hello"),
    text(" "),
    text("World!") | color(Color::Cyan) | bold,
  }) | border;

  // Render to screen
  auto screen = Screen::Create(
    Dimension::Fixed(20),
    Dimension::Fixed(5)
  );
  
  Render(screen, document);
  screen.Print();
  
  return 0;
}

Interactive Application

#include <ftxui/component/captured_mouse.hpp>
#include <ftxui/component/component.hpp>
#include <ftxui/component/component_base.hpp>
#include <ftxui/component/screen_interactive.hpp>
#include <ftxui/dom/elements.hpp>

using namespace ftxui;

int main() {
  // State variables
  std::string input_value;
  int slider_value = 50;
  bool checkbox_checked = false;
  int menu_selected = 0;
  
  // Create components
  auto input = Input(&input_value, "Enter name...");
  auto slider = Slider("Volume: ", &slider_value, 0, 100, 1);
  auto checkbox = Checkbox("Enable notifications", &checkbox_checked);
  
  std::vector<std::string> menu_items = {
    "New",
    "Open",
    "Save",
    "Exit"
  };
  auto menu = Menu(&menu_items, &menu_selected);
  
  // Layout
  auto container = Container::Vertical({
    input,
    slider,
    checkbox,
    menu,
  });
  
  // Renderer
  auto renderer = Renderer(container, [&] {
    return vbox({
      text("Settings") | bold | center,
      separator(),
      hbox({text("Name: "), input->Render()}),
      slider->Render(),
      checkbox->Render(),
      separator(),
      text("Menu:"),
      menu->Render() | frame | size(HEIGHT, LESS_THAN, 10),
      separator(),
      text("Input: " + input_value),
      text("Slider: " + std::to_string(slider_value)),
    }) | border;
  });
  
  auto screen = ScreenInteractive::TerminalOutput();
  screen.Loop(renderer);
  
  return 0;
}

Custom Components

#include <ftxui/component/component.hpp>
#include <ftxui/component/component_base.hpp>
#include <ftxui/dom/elements.hpp>

using namespace ftxui;

// Custom button component
class CustomButton : public ComponentBase {
private:
  std::string label_;
  std::function<void()> on_click_;
  bool hovered_ = false;
  
public:
  CustomButton(const std::string& label, std::function<void()> on_click)
      : label_(label), on_click_(on_click) {}
  
  Element Render() override {
    auto style = hovered_ ? inverted : nothing;
    return text("[ " + label_ + " ]") | style | reflect(box_);
  }
  
  bool OnEvent(Event event) override {
    if (event.is_mouse()) {
      auto mouse = event.mouse();
      hovered_ = box_.Contain(mouse.x, mouse.y);
      
      if (mouse.button == Mouse::Left && 
          mouse.motion == Mouse::Released &&
          hovered_) {
        on_click_();
        return true;
      }
    }
    
    if (event == Event::Return && Focused()) {
      on_click_();
      return true;
    }
    
    return false;
  }
  
  bool Focusable() const override { return true; }
  
private:
  Box box_;
};

// Usage example
int main() {
  int counter = 0;
  
  auto button = Make<CustomButton>("Click me!", [&] {
    counter++;
  });
  
  auto renderer = Renderer(button, [&] {
    return vbox({
      text("Counter: " + std::to_string(counter)) | center,
      separator(),
      button->Render() | center,
    }) | border | size(WIDTH, EQUAL, 30);
  });
  
  auto screen = ScreenInteractive::TerminalOutput();
  screen.Loop(renderer);
  
  return 0;
}

Animation

#include <ftxui/component/animation.hpp>
#include <ftxui/component/component.hpp>
#include <ftxui/component/screen_interactive.hpp>
#include <ftxui/dom/elements.hpp>
#include <chrono>

using namespace ftxui;
using namespace std::chrono_literals;

int main() {
  // Animation variables
  auto duration = 2s;
  auto start_time = std::chrono::steady_clock::now();
  
  auto component = Renderer([&] {
    auto now = std::chrono::steady_clock::now();
    auto elapsed = now - start_time;
    float progress = std::chrono::duration<float>(elapsed).count() / 
                    std::chrono::duration<float>(duration).count();
    progress = std::min(1.0f, progress);
    
    // Easing function
    auto ease_in_out = [](float t) {
      return t < 0.5f ? 2 * t * t : -1 + (4 - 2 * t) * t;
    };
    
    float animated_value = ease_in_out(progress);
    int position = static_cast<int>(animated_value * 40);
    
    return vbox({
      text("Animation Demo") | bold | center,
      separator(),
      hbox({
        text(std::string(position, ' ')),
        text("●") | color(Color::Red),
      }),
      separator(),
      gauge(progress) | color(Color::Blue),
      text("Progress: " + std::to_string(int(progress * 100)) + "%") | center,
    }) | border;
  });
  
  auto screen = ScreenInteractive::TerminalOutput();
  
  // Animation loop
  std::atomic<bool> refresh_ui_continue = true;
  std::thread refresh_ui([&] {
    while (refresh_ui_continue) {
      std::this_thread::sleep_for(16ms);
      screen.PostEvent(Event::Custom);
    }
  });
  
  screen.Loop(component);
  refresh_ui_continue = false;
  refresh_ui.join();
  
  return 0;
}

Advanced Features

Flexbox Layout

// Flexible layout using Flexbox
auto layout = flexbox({
  {
    text("Left") | border,
    FlexboxConfig().Set(FlexboxConfig::Direction::Column)
                   .Set(FlexboxConfig::Wrap::NoWrap)
                   .Set(FlexboxConfig::JustifyContent::Center)
  },
  {
    text("Center") | border | flex,
    FlexboxConfig().Set(FlexboxConfig::AlignItems::Center)
  },
  {
    text("Right") | border,
    FlexboxConfig().Set(FlexboxConfig::Basis, 20)
  },
});

Canvas Element

// Drawing with Canvas
auto canvas_element = canvas([](Canvas& c) {
  // High resolution drawing using Braille characters
  c.DrawText(10, 5, "Canvas Demo");
  c.DrawLine(0, 0, 40, 20);
  c.DrawCircle(20, 10, 5);
  
  // Using block characters
  c.DrawBlock(30, 15, true);
});

Modal Dialog

class ModalComponent : public ComponentBase {
private:
  bool show_modal_ = false;
  Component container_;
  
public:
  ModalComponent() {
    auto modal_content = Renderer([&] {
      return vbox({
        text("Confirm") | bold | center,
        separator(),
        text("Are you sure you want to exit?"),
        separator(),
        hbox({
          button("Yes", [&] { 
            show_modal_ = false;
            // Exit logic
          }),
          text(" "),
          button("No", [&] { 
            show_modal_ = false; 
          }),
        }) | center,
      }) | border | center;
    });
    
    auto main_content = button("Exit", [&] {
      show_modal_ = true;
    });
    
    container_ = Container::Tab(
      {main_content, modal_content},
      &show_modal_
    );
  }
  
  Element Render() override {
    return container_->Render();
  }
  
  bool OnEvent(Event event) override {
    return container_->OnEvent(event);
  }
};

Ecosystem

Related Projects

  • ftxui-starter: Project template
  • json-tui: JSON viewer
  • git-tui: Git client
  • spotify-tui: Spotify client

Build Systems

  • CMake: Native support
  • vcpkg: Package manager
  • Conan: Package manager
  • Bazel: Build system

Advantages

  • Modern Design: Functional & reactive programming
  • No Dependencies: Header-only for easy integration
  • Rich Features: Diverse components and layouts
  • High Performance: Efficient rendering
  • Cross-Platform: Windows, Linux, macOS support

Limitations

  • C++17 Required: Cannot use with older compilers
  • Learning Curve: Understanding functional paradigm required
  • Debugging: TUI app debugging is complex
  • Documentation: Limited non-English resources

Comparison with Other Libraries

FeatureFTXUIncursesImTui
ParadigmFunctionalImperativeImmediate Mode
DependenciesNoneSystemncurses
Learning CostMediumHighLow
ModernityVery HighLowHigh
FeaturesRichBasicModerate

Summary

FTXUI is an excellent library for developing TUI applications in modern C++. Its functional and reactive programming approach allows declarative construction of complex UIs, resulting in highly maintainable code. Being header-only with no dependencies makes project integration straightforward. It's particularly approachable for developers with web frontend experience, enabling efficient development of beautiful and interactive terminal applications.