diff --git a/include/ftxui/util/ref.hpp b/include/ftxui/util/ref.hpp
index e47743f9e4a285160a1926577f349151e6a4d950..a4d4b0b7ed5c86126a820599c2f2c4839a425f99 100644
--- a/include/ftxui/util/ref.hpp
+++ b/include/ftxui/util/ref.hpp
@@ -3,6 +3,7 @@
 
 #include <ftxui/screen/string.hpp>
 #include <string>
+#include <variant>
 
 namespace ftxui {
 
@@ -10,104 +11,85 @@ namespace ftxui {
 template <typename T>
 class ConstRef {
  public:
-  ConstRef() {}
-  ConstRef(T t) : owned_(t) {}
-  ConstRef(const T* t) : address_(t) {}
-  ConstRef(const ConstRef& t) : owned_(t.owned_), address_(t.address_) {}
-  ConstRef& operator=(const ConstRef& t) {
-    owned_ = t.owned_;
-    address_ = t.address_;
-    return *this;
-  }
-  const T& operator*() const { return address_ ? *address_ : owned_; }
-  const T& operator()() const { return address_ ? *address_ : owned_; }
-  const T* operator->() const { return address_ ? address_ : &owned_; }
+  ConstRef() = default;
+  ConstRef(const ConstRef<T>&) = default;
+  ConstRef(const T& t) : variant_(t) {}
+  ConstRef(const T* t) : variant_(t) {}
+
+  // Make a "resetable" reference
+  ConstRef<T>& operator=(const ConstRef<T>&) = default;
+
+  // Accessors:
+  const T& operator()() const { return *Address(); }
+  const T& operator*() const { return *Address(); }
+  const T* operator->() const { return Address(); }
 
  private:
-  T owned_;
-  const T* address_ = nullptr;
+  std::variant<T, const T*> variant_ = T{};
+
+  const T* Address() const {
+    return std::holds_alternative<T>(variant_) ? &std::get<T>(variant_)
+                                               : std::get<const T*>(variant_);
+  }
 };
 
 /// @brief An adapter. Own or reference an mutable object.
 template <typename T>
 class Ref {
  public:
-  Ref() {}
-  Ref(const T& t) : owned_(t) {}
-  Ref(T&& t) : owned_(std::forward<T>(t)) {}
-  Ref(T* t) : owned_(), address_(t) {}
-  Ref(const Ref& t) : owned_(t.owned_), address_(t.address_) {}
-  Ref& operator=(const Ref& t) {
-    owned_ = t.owned_;
-    address_ = t.address_;
-    return *this;
-  }
-  T& operator*() { return address_ ? *address_ : owned_; }
-  T& operator()() { return address_ ? *address_ : owned_; }
-  T* operator->() { return address_ ? address_ : &owned_; }
+  Ref() = default;
+  Ref(const Ref<T>&) = default;
+  Ref(const T& t) : variant_(t) {}
+  Ref(T&& t) : variant_(std::forward<T>(t)) {}
+  Ref(T* t) : variant_(t) {}
+
+  // Make a "resetable" reference
+  Ref<T>& operator=(const Ref<T>&) = default;
+
+  // Accessors:
+  T& operator()() { return *Address(); }
+  T& operator*() { return *Address(); }
+  T* operator->() { return Address(); }
+  const T& operator()() const { return *Address(); }
+  const T& operator*() const { return *Address(); }
+  const T* operator->() const { return Address(); }
 
  private:
-  T owned_;
-  T* address_ = nullptr;
+  std::variant<T, T*> variant_ = T{};
+
+  const T* Address() const {
+    return std::holds_alternative<T>(variant_) ? &std::get<T>(variant_)
+                                               : std::get<T*>(variant_);
+  }
+  T* Address() {
+    return std::holds_alternative<T>(variant_) ? &std::get<T>(variant_)
+                                               : std::get<T*>(variant_);
+  }
 };
 
 /// @brief An adapter. Own or reference a constant string. For convenience, this
 /// class convert multiple mutable string toward a shared representation.
-class StringRef {
+class StringRef : public Ref<std::string> {
  public:
-  StringRef(std::string* ref) : address_(ref) {}
-  StringRef(std::string ref) : owned_(std::move(ref)) {}
+  using Ref<std::string>::Ref;
+
   StringRef(const wchar_t* ref) : StringRef(to_string(std::wstring(ref))) {}
   StringRef(const char* ref) : StringRef(std::string(ref)) {}
-  StringRef(const StringRef& t) : owned_(t.owned_), address_(t.address_) {}
-  StringRef& operator=(const StringRef& t) {
-    owned_ = t.owned_;
-    address_ = t.address_;
-    return *this;
-  }
-  std::string& operator*() { return address_ ? *address_ : owned_; }
-  std::string& operator()() { return address_ ? *address_ : owned_; }
-  std::string* operator->() { return address_ ? address_ : &owned_; }
-
- private:
-  std::string owned_;
-  std::string* address_ = nullptr;
 };
 
 /// @brief An adapter. Own or reference a constant string. For convenience, this
 /// class convert multiple immutable string toward a shared representation.
-class ConstStringRef {
+class ConstStringRef : public ConstRef<std::string> {
  public:
-  ConstStringRef(const std::string* ref) : address_(ref) {}
+  using ConstRef<std::string>::ConstRef;
+
   ConstStringRef(const std::wstring* ref) : ConstStringRef(to_string(*ref)) {}
-  ConstStringRef(std::string ref) : owned_(std::move(ref)) {}
-  ConstStringRef(std::wstring ref) : ConstStringRef(to_string(ref)) {}
-  ConstStringRef(const wchar_t* ref) : ConstStringRef(std::wstring(ref)) {}
-  ConstStringRef(const char* ref)
-      : ConstStringRef(to_wstring(std::string(ref))) {}
-  ConstStringRef(const ConstStringRef& t)
-      : owned_(t.owned_), address_(t.address_) {}
-  ConstStringRef& operator=(const ConstStringRef& t) {
-    owned_ = t.owned_;
-    address_ = t.address_;
-    return *this;
-  }
-  ConstStringRef& operator=(ConstStringRef&& t) {
-    owned_ = std::move(t.owned_);
-    address_ = t.address_;
-    return *this;
-  }
-  const std::string& operator()() const {
-    return address_ ? *address_ : owned_;
-  }
-  const std::string& operator*() const { return address_ ? *address_ : owned_; }
-  const std::string* operator->() const {
-    return address_ ? address_ : &owned_;
-  }
+  ConstStringRef(const std::wstring ref) : ConstStringRef(to_string(ref)) {}
+  ConstStringRef(const wchar_t* ref)
+      : ConstStringRef(to_string(std::wstring(ref))) {}
+  ConstStringRef(const char* ref) : ConstStringRef(std::string(ref)) {}
 
- private:
-  std::string owned_;
-  const std::string* address_ = nullptr;
+  ConstStringRef& operator=(const ConstStringRef&) = default;
 };
 
 /// @brief An adapter. Reference a list of strings.
diff --git a/src/ftxui/component/input.cpp b/src/ftxui/component/input.cpp
index 0f32946e337803732b58edb5f34d1d89d6e292b2..cd5b070a51dc2af6c53fabbe818fa2fd7a465ef9 100644
--- a/src/ftxui/component/input.cpp
+++ b/src/ftxui/component/input.cpp
@@ -568,7 +568,7 @@ Component Input(InputOption option) {
 /// placeholder
 /// ```
 Component Input(StringRef content, InputOption option) {
-  option.content = content;
+  option.content = std::move(content);
   return Make<InputBase>(std::move(option));
 }
 
@@ -594,8 +594,8 @@ Component Input(StringRef content, InputOption option) {
 /// placeholder
 /// ```
 Component Input(StringRef content, StringRef placeholder, InputOption option) {
-  option.content = content;
-  option.placeholder = placeholder;
+  option.content = std::move(content);
+  option.placeholder = std::move(placeholder);
   return Make<InputBase>(std::move(option));
 }
 
diff --git a/src/ftxui/dom/canvas.cpp b/src/ftxui/dom/canvas.cpp
index db8a6998783f5997e244aa020e02dee4694f0914..f42efb66d4e8a7d975ecdf7ec1c95a3a6b64fede 100644
--- a/src/ftxui/dom/canvas.cpp
+++ b/src/ftxui/dom/canvas.cpp
@@ -849,15 +849,14 @@ class CanvasNodeBase : public Node {
 Element canvas(ConstRef<Canvas> canvas) {
   class Impl : public CanvasNodeBase {
    public:
-    // NOLINTNEXTLINE
-    explicit Impl(ConstRef<Canvas> canvas) : canvas_(std::move(canvas)) {
+    explicit Impl(ConstRef<Canvas> canvas) : canvas_(canvas) {
       requirement_.min_x = (canvas_->width() + 1) / 2;
       requirement_.min_y = (canvas_->height() + 3) / 4;
     }
     const Canvas& canvas() final { return *canvas_; }
     ConstRef<Canvas> canvas_;
   };
-  return std::make_shared<Impl>(std::move(canvas));
+  return std::make_shared<Impl>(canvas);
 }
 
 /// @brief Produce an element drawing a canvas of requested size.