diff --git a/CHANGELOG.md b/CHANGELOG.md
index cfe7ad694d9b777edb94b1aa1eb6c684e693d263..a0afeb2ed9465563fc7bf9868bb8dc21ba5eb3ad 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -43,6 +43,11 @@ current (development)
 
 ### Screen
 - Feature: Add `Box::IsEmpty()`.
+- Feature: Color transparency
+    - Add `Color::RGBA(r,g,b,a)`.
+    - Add `Color::HSVA(r,g,b,a)`.
+    - Add `Color::Blend(Color)`.
+    - Add `Color::IsOpaque()`
 
 ### Util
 - Feature: Support arbitrary `Adapter` for `ConstStringListRef`. See #843.
diff --git a/include/ftxui/screen/color.hpp b/include/ftxui/screen/color.hpp
index 52f699b5e59e41026f1b1f6ed6a67ff285752b1d..1489dca634982cd31efee4b2ce6e21f63c070239 100644
--- a/include/ftxui/screen/color.hpp
+++ b/include/ftxui/screen/color.hpp
@@ -29,10 +29,16 @@ class Color {
   Color(Palette16 index);   // Implicit conversion from index to Color.
   Color(Palette256 index);  // Implicit conversion from index to Color.
   // NOLINTEND
-  Color(uint8_t red, uint8_t green, uint8_t blue);
+  Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255);
   static Color RGB(uint8_t red, uint8_t green, uint8_t blue);
   static Color HSV(uint8_t hue, uint8_t saturation, uint8_t value);
+  static Color RGBA(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha);
+  static Color HSVA(uint8_t hue,
+                    uint8_t saturation,
+                    uint8_t value,
+                    uint8_t alpha);
   static Color Interpolate(float t, const Color& a, const Color& b);
+  static Color Blend(const Color& lhs, const Color& rhs);
 
   //---------------------------
   // List of colors:
@@ -310,6 +316,7 @@ class Color {
   bool operator!=(const Color& rhs) const;
 
   std::string Print(bool is_background_color) const;
+  bool IsOpaque() const { return alpha_ == 255; }
 
  private:
   enum class ColorType : uint8_t {
@@ -322,6 +329,7 @@ class Color {
   uint8_t red_ = 0;
   uint8_t green_ = 0;
   uint8_t blue_ = 0;
+  uint8_t alpha_ = 0;
 };
 
 inline namespace literals {
diff --git a/include/ftxui/screen/pixel.hpp b/include/ftxui/screen/pixel.hpp
index 0a58a389802d6bf5f78167691700159eeb8f6621..7545d1ef8873f3b64a1842c675a10748b6062e71 100644
--- a/include/ftxui/screen/pixel.hpp
+++ b/include/ftxui/screen/pixel.hpp
@@ -38,7 +38,7 @@ struct Pixel {
 
   // The graphemes stored into the pixel. To support combining characters,
   // like: a?, this can potentially contain multiple codepoints.
-  std::string character = " ";
+  std::string character = "";
 
   // Colors:
   Color background_color = Color::Default;
diff --git a/src/ftxui/dom/clear_under.cpp b/src/ftxui/dom/clear_under.cpp
index a18510dfae0032a101fc309602546740c1ad22cd..81dc2bfce14524bc385b9c67a2a2b993dd0347c9 100644
--- a/src/ftxui/dom/clear_under.cpp
+++ b/src/ftxui/dom/clear_under.cpp
@@ -23,6 +23,7 @@ class ClearUnder : public NodeDecorator {
     for (int y = box_.y_min; y <= box_.y_max; ++y) {
       for (int x = box_.x_min; x <= box_.x_max; ++x) {
         screen.PixelAt(x, y) = Pixel();
+        screen.PixelAt(x, y).character = " ";  // Consider the pixel written.
       }
     }
     Node::Render(screen);
diff --git a/src/ftxui/dom/color.cpp b/src/ftxui/dom/color.cpp
index 238ccca63664ca9a1cdecdf6739c381d9d20e4a8..431d522eb6ab34af5078b099c1848d134cd2753a 100644
--- a/src/ftxui/dom/color.cpp
+++ b/src/ftxui/dom/color.cpp
@@ -19,9 +19,18 @@ class BgColor : public NodeDecorator {
       : NodeDecorator(std::move(child)), color_(color) {}
 
   void Render(Screen& screen) override {
-    for (int y = box_.y_min; y <= box_.y_max; ++y) {
-      for (int x = box_.x_min; x <= box_.x_max; ++x) {
-        screen.PixelAt(x, y).background_color = color_;
+    if (color_.IsOpaque()) {
+      for (int y = box_.y_min; y <= box_.y_max; ++y) {
+        for (int x = box_.x_min; x <= box_.x_max; ++x) {
+          screen.PixelAt(x, y).background_color = color_;
+        }
+      }
+    } else {
+      for (int y = box_.y_min; y <= box_.y_max; ++y) {
+        for (int x = box_.x_min; x <= box_.x_max; ++x) {
+          Color& color = screen.PixelAt(x, y).background_color;
+          color = Color::Blend(color, color_);
+        }
       }
     }
     NodeDecorator::Render(screen);
@@ -36,9 +45,18 @@ class FgColor : public NodeDecorator {
       : NodeDecorator(std::move(child)), color_(color) {}
 
   void Render(Screen& screen) override {
-    for (int y = box_.y_min; y <= box_.y_max; ++y) {
-      for (int x = box_.x_min; x <= box_.x_max; ++x) {
-        screen.PixelAt(x, y).foreground_color = color_;
+    if (color_.IsOpaque()) {
+      for (int y = box_.y_min; y <= box_.y_max; ++y) {
+        for (int x = box_.x_min; x <= box_.x_max; ++x) {
+          screen.PixelAt(x, y).foreground_color = color_;
+        }
+      }
+    } else {
+      for (int y = box_.y_min; y <= box_.y_max; ++y) {
+        for (int x = box_.x_min; x <= box_.x_max; ++x) {
+          Color& color = screen.PixelAt(x, y).foreground_color;
+          color = Color::Blend(color, color_);
+        }
       }
     }
     NodeDecorator::Render(screen);
@@ -46,6 +64,7 @@ class FgColor : public NodeDecorator {
 
   Color color_;
 };
+
 }  // namespace
 
 /// @brief Set the foreground color of an element.
diff --git a/src/ftxui/dom/dbox.cpp b/src/ftxui/dom/dbox.cpp
index 92971c81fe67bc120651ec867e831e8577019753..a75321550437a85be6ff1b31302940a34550c495 100644
--- a/src/ftxui/dom/dbox.cpp
+++ b/src/ftxui/dom/dbox.cpp
@@ -46,6 +46,57 @@ class DBox : public Node {
       child->SetBox(box);
     }
   }
+
+  void Render(Screen& screen) override {
+    if (children_.size() <= 1) {
+      return Node::Render(screen);
+    }
+
+    const int width = box_.x_max - box_.x_min + 1;
+    const int height = box_.y_max - box_.y_min + 1;
+    std::vector<Pixel> pixels(size_t(width * height));
+
+    for (auto& child : children_) {
+      child->Render(screen);
+
+      // Accumulate the pixels
+      Pixel* acc = pixels.data();
+      for (int x = 0; x < width; ++x) {
+        for (int y = 0; y < height; ++y) {
+          auto& pixel = screen.PixelAt(x + box_.x_min, y + box_.y_min);
+          acc->background_color =
+              Color::Blend(acc->background_color, pixel.background_color);
+          acc->automerge = pixel.automerge || acc->automerge;
+          if (pixel.character == "") {
+            acc->foreground_color =
+                Color::Blend(acc->foreground_color, pixel.background_color);
+          } else {
+            acc->blink = pixel.blink;
+            acc->bold = pixel.bold;
+            acc->dim = pixel.dim;
+            acc->inverted = pixel.inverted;
+            acc->underlined = pixel.underlined;
+            acc->underlined_double = pixel.underlined_double;
+            acc->strikethrough = pixel.strikethrough;
+            acc->hyperlink = pixel.hyperlink;
+            acc->character = pixel.character;
+            acc->foreground_color = pixel.foreground_color;
+          }
+          ++acc;
+
+          pixel = Pixel();
+        }
+      }
+    }
+
+    // Render the accumulated pixels:
+    Pixel* acc = pixels.data();
+    for (int x = 0; x < width; ++x) {
+      for (int y = 0; y < height; ++y) {
+        screen.PixelAt(x + box_.x_min, y + box_.y_min) = *acc++;
+      }
+    }
+  }
 };
 }  // namespace
 
diff --git a/src/ftxui/screen/color.cpp b/src/ftxui/screen/color.cpp
index a70ec87249a0d56703a30462a88bea324a9bfb30..546241f7319f05f0e6d4e92107108536cfc72403 100644
--- a/src/ftxui/screen/color.cpp
+++ b/src/ftxui/screen/color.cpp
@@ -73,13 +73,15 @@ Color::Color() = default;
 /// @ingroup screen
 Color::Color(Palette1 /*value*/) : Color() {}
 
-/// @brief Build a transparent using Palette16 colors.
+/// @brief Build a color using the Palette16 colors.
 /// @ingroup screen
-Color::Color(Palette16 index) : type_(ColorType::Palette16), red_(index) {}
+Color::Color(Palette16 index)
+    : type_(ColorType::Palette16), red_(index), alpha_(255) {}
 
-/// @brief Build a transparent using Palette256 colors.
+/// @brief Build a color using Palette256 colors.
 /// @ingroup screen
-Color::Color(Palette256 index) : type_(ColorType::Palette256), red_(index) {
+Color::Color(Palette256 index)
+    : type_(ColorType::Palette256), red_(index), alpha_(255) {
   if (Terminal::ColorSupport() >= Terminal::Color::Palette256) {
     return;
   }
@@ -93,9 +95,14 @@ Color::Color(Palette256 index) : type_(ColorType::Palette256), red_(index) {
 /// @param red The quantity of red [0,255]
 /// @param green The quantity of green [0,255]
 /// @param blue The quantity of blue [0,255]
+/// @param alpha The quantity of alpha [0,255]
 /// @ingroup screen
-Color::Color(uint8_t red, uint8_t green, uint8_t blue)
-    : type_(ColorType::TrueColor), red_(red), green_(green), blue_(blue) {
+Color::Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
+    : type_(ColorType::TrueColor),
+      red_(red),
+      green_(green),
+      blue_(blue),
+      alpha_(alpha) {
   if (Terminal::ColorSupport() == Terminal::Color::TrueColor) {
     return;
   }
@@ -136,7 +143,20 @@ Color::Color(uint8_t red, uint8_t green, uint8_t blue)
 /// @ingroup screen
 // static
 Color Color::RGB(uint8_t red, uint8_t green, uint8_t blue) {
-  return {red, green, blue};
+  return RGBA(red, green, blue, 255);
+}
+
+/// @brief Build a Color from its RGBA representation.
+/// https://en.wikipedia.org/wiki/RGB_color_model
+/// @param red The quantity of red [0,255]
+/// @param green The quantity of green [0,255]
+/// @param blue The quantity of blue [0,255]
+/// @param alpha The quantity of alpha [0,255]
+/// @ingroup screen
+/// @see Color::RGB
+// static
+Color Color::RGBA(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) {
+  return {red, green, blue, alpha};
 }
 
 /// @brief Build a Color from its HSV representation.
@@ -145,9 +165,10 @@ Color Color::RGB(uint8_t red, uint8_t green, uint8_t blue) {
 /// @param h The hue of the color [0,255]
 /// @param s The "colorfulness" [0,255].
 /// @param v The "Lightness" [0,255]
+/// @param alpha The quantity of alpha [0,255]
 /// @ingroup screen
 // static
-Color Color::HSV(uint8_t h, uint8_t s, uint8_t v) {
+Color Color::HSVA(uint8_t h, uint8_t s, uint8_t v, uint8_t alpha) {
   uint8_t region = h / 43;                                        // NOLINT
   uint8_t remainder = (h - (region * 43)) * 6;                    // NOLINT
   uint8_t p = (v * (255 - s)) >> 8;                               // NOLINT
@@ -155,16 +176,28 @@ Color Color::HSV(uint8_t h, uint8_t s, uint8_t v) {
   uint8_t t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;  // NOLINT
 
   // clang-format off
-  switch (region) {              // NOLINT
-    case 0: return Color(v,t,p); // NOLINT
-    case 1: return Color(q,v,p); // NOLINT
-    case 2: return Color(p,v,t); // NOLINT
-    case 3: return Color(p,q,v); // NOLINT
-    case 4: return Color(t,p,v); // NOLINT
-    case 5: return Color(v,p,q); // NOLINT
-  }                              // NOLINT
+  switch (region) {                     // NOLINT
+    case 0: return Color(v,t,p, alpha); // NOLINT
+    case 1: return Color(q,v,p, alpha); // NOLINT
+    case 2: return Color(p,v,t, alpha); // NOLINT
+    case 3: return Color(p,q,v, alpha); // NOLINT
+    case 4: return Color(t,p,v, alpha); // NOLINT
+    case 5: return Color(v,p,q, alpha); // NOLINT
+  }                                     // NOLINT
   // clang-format on
-  return {0, 0, 0};
+  return {0, 0, 0, alpha};
+}
+
+/// @brief Build a Color from its HSV representation.
+/// https://en.wikipedia.org/wiki/HSL_and_HSV
+///
+/// @param h The hue of the color [0,255]
+/// @param s The "colorfulness" [0,255].
+/// @param v The "Lightness" [0,255]
+/// @ingroup screen
+// static
+Color Color::HSV(uint8_t h, uint8_t s, uint8_t v) {
+  return HSVA(h, s, v, 255);
 }
 
 // static
@@ -235,6 +268,14 @@ Color Color::Interpolate(float t, const Color& a, const Color& b) {
                     interp(a_b, b_b));  //
 }
 
+/// @brief Blend two colors together using the alpha channel.
+// static
+Color Color::Blend(const Color& lhs, const Color& rhs) {
+  Color out = Interpolate(float(rhs.alpha_) / 255.F, lhs, rhs);
+  out.alpha_ = lhs.alpha_ + rhs.alpha_ - lhs.alpha_ * rhs.alpha_ / 255;
+  return out;
+}
+
 inline namespace literals {
 
 Color operator""_rgb(unsigned long long int combined) {
diff --git a/src/ftxui/screen/screen.cpp b/src/ftxui/screen/screen.cpp
index 1a272baaa9cd3a6fb07c5a339178bdd4e013df7a..a04914a0a48725032f0aee61df7f5caa4691c7b0 100644
--- a/src/ftxui/screen/screen.cpp
+++ b/src/ftxui/screen/screen.cpp
@@ -423,7 +423,11 @@ std::string Screen::ToString() const {
       if (!previous_fullwidth) {
         UpdatePixelStyle(this, ss, *previous_pixel_ref, pixel);
         previous_pixel_ref = &pixel;
-        ss << pixel.character;
+        if (pixel.character.empty()) {
+          ss << " ";
+        } else {
+          ss << pixel.character;
+        }
       }
       previous_fullwidth = (string_width(pixel.character) == 2);
     }