diff --git a/.gitlab/artifacts.yml b/.gitlab/artifacts.yml
index 40e5ca73f8aad06f49f0a25d312bf62b3604fcff..4a70ec7c7e17b717d8bf1049c52259b31d14958c 100644
--- a/.gitlab/artifacts.yml
+++ b/.gitlab/artifacts.yml
@@ -67,6 +67,10 @@
             # Virtual environment
             - build/ci-venv/
 
+            # QML artifacts
+            - build/*/*/qmldir
+            - build/*/*/VTK.qmltypes
+
 .cmake_test_artifacts:
     artifacts:
         expire_in: 1d
diff --git a/.gitlab/ci/ctest_exclusions.cmake b/.gitlab/ci/ctest_exclusions.cmake
index 69e9bf266aab933d7aad111e84ec4b1d233638a6..a20b6f78fd697944dff8bbbad1d95f78253c2ab1 100644
--- a/.gitlab/ci/ctest_exclusions.cmake
+++ b/.gitlab/ci/ctest_exclusions.cmake
@@ -18,6 +18,9 @@ if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "fedora")
     # Numerical problems?
     "^VTK::FiltersOpenTURNSCxx-TestOTKernelSmoothing$"
 
+    # QtQuick event loop issue with CI VNC
+    "^VTK::GUISupportQtQuickCxx-TestQQuickVTKRenderItemWidget$"
+
     # These tests all seem to have some problem with the rendering order of
     # some components of the scenes that are being tested. Needs investigation.
     # https://gitlab.kitware.com/vtk/vtk/-/issues/18098
@@ -146,7 +149,10 @@ if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "windows")
     "^VTK::GUISupportQtCxx-TestQVTKOpenGLWidgetPicking$"
     "^VTK::GUISupportQtCxx-TestQVTKOpenGLWidgetQWidgetWidget$"
     "^VTK::GUISupportQtCxx-TestQVTKOpenGLWidgetWithDisabledInteractor$"
-    "^VTK::GUISupportQtCxx-TestQVTKOpenGLWidgetWithMSAA$")
+    "^VTK::GUISupportQtCxx-TestQVTKOpenGLWidgetWithMSAA$"
+    "^VTK::GUISupportQtQuickCxx-TestQQuickVTKRenderItem$"
+    "^VTK::GUISupportQtQuickCxx-TestQQuickVTKRenderItemWidget$"
+    "^VTK::GUISupportQtQuickCxx-TestQQuickVTKRenderWindow$")
 endif ()
 
 if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "osmesa")
@@ -158,6 +164,14 @@ if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "osmesa")
     "^VTK::RenderingOpenGL2Cxx-TestGlyph3DMapperPickability$")
 endif ()
 
+if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "macos")
+  list(APPEND test_exclusions
+    # QtQuick event loop / OpenGL context issues. Needs investigation
+    "^VTK::GUISupportQtQuickCxx-TestQQuickVTKRenderItem$"
+    "^VTK::GUISupportQtQuickCxx-TestQQuickVTKRenderItemWidget$"
+    "^VTK::GUISupportQtQuickCxx-TestQQuickVTKRenderWindow$")
+endif ()
+
 string(REPLACE ";" "|" test_exclusions "${test_exclusions}")
 if (test_exclusions)
   set(test_exclusions "(${test_exclusions})")
diff --git a/.gitlab/ci/docker/fedora33/install_deps.sh b/.gitlab/ci/docker/fedora33/install_deps.sh
index 3ad09ed4df8f1d1af5a829c68902ffae0b2fc9e0..9339c24fcde58fd7a7a0948cbf036ca9838d223e 100755
--- a/.gitlab/ci/docker/fedora33/install_deps.sh
+++ b/.gitlab/ci/docker/fedora33/install_deps.sh
@@ -19,7 +19,7 @@ dnf install -y --setopt=install_weak_deps=False \
 
 # Qt dependencies
 dnf install -y --setopt=install_weak_deps=False \
-    qt5-qtbase-devel qt5-qttools-devel
+    qt5-qtbase-devel qt5-qttools-devel qt5-qtquickcontrols2-devel
 
 # Mesa dependencies
 dnf install -y --setopt=install_weak_deps=False \
diff --git a/.gitlab/ci/download_qt.cmake b/.gitlab/ci/download_qt.cmake
index 0ea2e667560762680f01c2197506b453c73dd491..b6a0492a7fd8c5d5cee4a5208bb85a4c6a773ced 100644
--- a/.gitlab/ci/download_qt.cmake
+++ b/.gitlab/ci/download_qt.cmake
@@ -47,7 +47,7 @@ if (qt_platform STREQUAL "windows_x86")
     "${qt_file_name_prefix}d3dcompiler_47-x64.7z"
     "${qt_file_name_prefix}opengl32sw-64-mesa_12_0_rc2.7z")
 
-  foreach (qt_component IN ITEMS qtbase qttools)
+  foreach (qt_component IN ITEMS qtbase qttools qtdeclarative qtquickcontrols2)
     list(APPEND qt_files
       "${qt_file_name_prefix}${qt_component}-Windows-Windows_10-MSVC${msvc_year}-Windows-Windows_10-X86_64.7z")
   endforeach ()
@@ -57,7 +57,7 @@ elseif (qt_platform STREQUAL "mac_x64")
   set(qt_build_stamp "202009071110")
   set(qt_file_name_prefix "${qt_version}-0-${qt_build_stamp}")
 
-  foreach (qt_component IN ITEMS qtbase qttools)
+  foreach (qt_component IN ITEMS qtbase qttools qtdeclarative qtquickcontrols2)
     list(APPEND qt_files
       "${qt_file_name_prefix}${qt_component}-MacOS-MacOS_10_13-Clang-MacOS-MacOS_10_13-X86_64.7z")
   endforeach ()
diff --git a/.gitlab/ci/download_qt_hashes.cmake b/.gitlab/ci/download_qt_hashes.cmake
index 5b4b0da83fede9e0b7e22322fc9b32e9bc669977..93596d1abaaaf7a9ceaa3c61bd60f66ad6401bd5 100644
--- a/.gitlab/ci/download_qt_hashes.cmake
+++ b/.gitlab/ci/download_qt_hashes.cmake
@@ -4,6 +4,8 @@
 
 set("5.15.1-0-202009071110qtbase-Windows-Windows_10-MSVC2019-Windows-Windows_10-X86_64.7z_hash" a5635124a135f383d9fb92bf628b018cff9f781addfd388926a367cda5b7cd38)
 set("5.15.1-0-202009071110qttools-Windows-Windows_10-MSVC2019-Windows-Windows_10-X86_64.7z_hash" 45b3debfc317f875d327e4506c0d211dc82ec92c1e9aa60e17b1a747ada22811)
+set("5.15.1-0-202009071110qtdeclarative-Windows-Windows_10-MSVC2019-Windows-Windows_10-X86_64.7z_hash" c40623f08fb54f0f46758b863d79d88449c04044415eb133b61df02055edd028)
+set("5.15.1-0-202009071110qtquickcontrols2-Windows-Windows_10-MSVC2019-Windows-Windows_10-X86_64.7z_hash" e09fa3e44bc3edb102963a197f2d1e8444d6ad0b1cae6e2da27fb423c9c62d76)
 
 # There's a filename conflict here.
 if (msvc_year STREQUAL "2019")
@@ -15,6 +17,10 @@ elseif (msvc_year STREQUAL "2015")
 endif ()
 set("5.15.1-0-202009071110qtbase-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z_hash" 5d0d2e71e3b00cf88ac4c616b4b314a7e73871f325512821f53c464cdfee961f)
 set("5.15.1-0-202009071110qttools-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z_hash" 393630ea20cc5fa29e7987df21526586bcac23c3499fb9889d980758942f942e)
+set("5.15.1-0-202009071110qtdeclarative-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z_hash" a40ece71b5685de946084b04642cbd9b80cf51e82b17c3cbdfb926f8ae6063e9)
+set("5.15.1-0-202009071110qtquickcontrols2-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z_hash" ef1ea627321bb0a36684dc02303aaf56f667672262cd3c74097397177f53981e)
 
 set("5.15.1-0-202009071110qtbase-MacOS-MacOS_10_13-Clang-MacOS-MacOS_10_13-X86_64.7z_hash" df2813ce7c6cb4287abd7956cd1cb9d08312e4ac1208b6cb57af4df11b8ebba1)
 set("5.15.1-0-202009071110qttools-MacOS-MacOS_10_13-Clang-MacOS-MacOS_10_13-X86_64.7z_hash" 94c5e98afa548bf56c7ccc29bccf727b75e2e90df98e83d22575d07f64359cda)
+set("5.15.1-0-202009071110qtdeclarative-MacOS-MacOS_10_13-Clang-MacOS-MacOS_10_13-X86_64.7z_hash" 9a23e1a2771a2a202b73c640e2eab032c480c2037e22842a113fca9e0f234c46)
+set("5.15.1-0-202009071110qtquickcontrols2-MacOS-MacOS_10_13-Clang-MacOS-MacOS_10_13-X86_64.7z_hash" fc305bbdf6e6301dbb0b9b8c7466b5a57ce8ee2ffb0a8a438a273639b62236c5)
diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml
index 31b5b80b3ed21c808d95b73619ce14a728321fd8..300e3cd3223d9b91eea0c358e391fc8abc73b627 100644
--- a/.gitlab/os-linux.yml
+++ b/.gitlab/os-linux.yml
@@ -9,7 +9,7 @@
 
 .fedora33:
     extends: .linux
-    image: "kitware/vtk:ci-fedora33-20210419"
+    image: "kitware/vtk:ci-fedora33-20210426"
 
 .fedora_mpich_addon:
     variables:
diff --git a/Documentation/release/dev/qtquick-qml-support.md b/Documentation/release/dev/qtquick-qml-support.md
new file mode 100644
index 0000000000000000000000000000000000000000..3fdcfe495b8dc538919eccec05cadcbf03fc1698
--- /dev/null
+++ b/Documentation/release/dev/qtquick-qml-support.md
@@ -0,0 +1,6 @@
+# QtQuick / QML support
+
+VTK can now be used in a QtQuick / QML application.
+
+A new module `vtkGUISupportQtQuick` provides the necessary integration classes along with the QML
+module infrastructure required to import VTK into a QtQuick application.
diff --git a/GUISupport/QtQuick/CMakeLists.txt b/GUISupport/QtQuick/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ec5e5f2bac4dea360185a640110671d551738f85
--- /dev/null
+++ b/GUISupport/QtQuick/CMakeLists.txt
@@ -0,0 +1,183 @@
+set(classes
+  QQmlVTKPlugin
+  QQuickVTKInteractiveWidget
+  QQuickVTKInteractorAdapter
+  QQuickVTKRenderItem
+  QQuickVTKRenderWindow
+  )
+
+include(vtkQt)
+set(qt_components
+  Gui
+  OpenGL
+  Quick
+  Qml
+  )
+
+vtk_module_find_package(
+  PACKAGE     "Qt${vtk_qt_major_version}"
+  VERSION     5.9
+  COMPONENTS  ${qt_components}
+  FORWARD_VERSION_REQ MINOR
+  VERSION_VAR         "Qt${vtk_qt_major_version}_VERSION")
+
+set(CMAKE_AUTOMOC 1)
+
+vtk_module_add_module(VTK::GUISupportQtQuick
+  CLASSES ${classes}
+  )
+
+foreach(_qt_comp IN LISTS qt_components)
+  list(APPEND qt_modules "Qt${vtk_qt_major_version}::${_qt_comp}")
+endforeach()
+
+vtk_module_definitions(VTK::GUISupportQtQuick PRIVATE QT_NO_KEYWORDS)
+vtk_module_link(VTK::GUISupportQtQuick PUBLIC ${qt_modules})
+
+_vtk_module_real_target(vtk_guisupportqtquick_target VTK::GUISupportQtQuick)
+
+# Generate the qmldir file for module plugin consumption in a Qml project
+
+# QML plugin qmldir and qmltypes for build tree
+# Set VTK_MODULE_PLUGIN_NAME and VTK_MODULE_PLUGIN_DIR for the qmldir configuration
+set(vtk_qml_module_dir
+  ${_vtk_build_PACKAGE}.${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION})
+set(vtk_qml_module_superpath
+  ${CMAKE_BINARY_DIR}/$<CONFIG>)
+set(vtk_qml_module_path
+  ${vtk_qml_module_superpath}/${vtk_qml_module_dir})
+
+# We use a three step approach to resolving the QML plugin path for qmldir file
+# during compilation of this module.
+# The first step would be to configure the qmldir.in file to a pre-generator
+# file. This step would be followed by a generator step that fills in the right
+# directory location for VTK and generates a qmldir file for each
+# possible build configuration i.e. Debug, Release, etc.
+# The third step is to copy the right configuration file to the plugin
+# location at build time. This is done as a custom command.
+set(VTK_MODULE_PLUGIN_NAME "$<TARGET_FILE_BASE_NAME:${vtk_guisupportqtquick_target}>")
+set(VTK_MODULE_PLUGIN_DIR "$<TARGET_FILE_DIR:${vtk_guisupportqtquick_target}>")
+set(vtk_qml_module_tmp_build_path
+  ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/qmldirBuild
+  )
+set(qmldir_pregen_file
+  "${vtk_qml_module_tmp_build_path}/qmldir.pregen")
+configure_file(
+  ${CMAKE_CURRENT_SOURCE_DIR}/qmldir.in
+  ${qmldir_pregen_file}
+  @ONLY
+  )
+set(qmldir_gen_file
+  "${vtk_qml_module_tmp_build_path}/qmldir$<CONFIG>.gen")
+file(GENERATE OUTPUT ${qmldir_gen_file}
+  INPUT ${qmldir_pregen_file})
+add_custom_command(TARGET ${vtk_guisupportqtquick_target}
+  POST_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy_if_different
+    ${qmldir_gen_file} ${vtk_qml_module_path}/qmldir
+  WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+  # Commented out because generator expreesions not supported in CMake < 3.20 for byproducts
+  # BYPRODUCTS ${vtk_qml_module_path}/qmldir
+  COMMENT "Generating qmldir file"
+  VERBATIM
+  )
+
+# Generate the qmltypes file for the VTK Qml plugin
+# First, find the qmlplugindump executable
+get_target_property(qt_core_location Qt${vtk_qt_major_version}::Core LOCATION)
+get_filename_component(qt_bin_dir "${qt_core_location}" PATH)
+if(APPLE)
+  get_filename_component(qt_bin_dir "${qt_bin_dir}" PATH)
+endif()
+find_program(QMLPLUGINDUMP_EXECUTABLE qmlplugindump
+  HINTS "${qt_bin_dir}"
+  DOC "QmlPlugindump executable location"
+  )
+mark_as_advanced(QMLPLUGINDUMP_EXECUTABLE)
+if(NOT QMLPLUGINDUMP_EXECUTABLE)
+  message(WARNING "qmlplugindump executable not found.\n"
+                  "It is required to generate the qmltypes file"
+                  " for VTK Qml plugin.")
+endif()
+
+set(qmltypes_file
+  "${vtk_qml_module_path}/${_vtk_build_PACKAGE}.qmltypes"
+  )
+set(qmltypes_create_copy_command FALSE)
+if(QMLPLUGINDUMP_EXECUTABLE)
+  get_target_property(qt_config Qt${vtk_qt_major_version}::Core IMPORTED_CONFIGURATIONS)
+  if(("DEBUG" IN_LIST qt_config) AND ("RELEASE" IN_LIST qt_config))
+    MESSAGE (WARNING "Qt5 is configured in both Debug and Release modes."
+      " Due to Qt issue 47774 (https://bugreports.qt.io/browse/QTBUG-47774),"
+      " skipping generation of qmltypes file."
+      " Using the one provided with the source tree instead.")
+    set(qmltypes_create_copy_command TRUE)
+  else()
+    add_custom_command(TARGET ${vtk_guisupportqtquick_target}
+      POST_BUILD
+      COMMAND
+        ${QMLPLUGINDUMP_EXECUTABLE} ${_vtk_build_PACKAGE}
+        ${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}
+        ${vtk_qml_module_superpath} > ${qmltypes_file}
+      WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+      # BYPRODUCTS ${qmltypes_file}
+      COMMENT "Generating qmltypes file using qmlplugindump"
+      VERBATIM
+      )
+  endif()
+else()
+  set(qmltypes_create_copy_command TRUE)
+endif()
+if(qmltypes_create_copy_command)
+  add_custom_command(TARGET ${vtk_guisupportqtquick_target}
+    POST_BUILD
+    COMMAND
+      ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${_vtk_build_PACKAGE}.qmltypes
+        ${vtk_qml_module_path}
+    COMMENT "Copying qmltypes file from the source tree to ${vtk_qml_module_path}"
+    )
+endif()
+
+# QML plugin qmldir and qmltypes for install tree
+set(vtk_qml_module_tmp_install_path
+  ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/qmldirInstall
+  )
+set(vtk_qml_module_install_path
+  ${vtk_qml_module_tmp_install_path}/$<CONFIG>/${vtk_qml_module_dir})
+if(WIN32 AND NOT CYGWIN)
+  # Set VTK_MODULE_PLUGIN_DIR for the qmldir configuration
+  # Use the runtime (dll) path for plugin on Windows
+  file(RELATIVE_PATH VTK_MODULE_PLUGIN_DIR
+    ${CMAKE_INSTALL_PREFIX}/${_vtk_build_PACKAGE}
+    ${CMAKE_INSTALL_PREFIX}/${_vtk_build_RUNTIME_DESTINATION}
+    )
+else()
+  # Set VTK_MODULE_PLUGIN_DIR for the qmldir configuration
+  file(RELATIVE_PATH VTK_MODULE_PLUGIN_DIR
+    ${CMAKE_INSTALL_PREFIX}/${_vtk_build_PACKAGE}
+    ${CMAKE_INSTALL_PREFIX}/${_vtk_build_LIBRARY_DESTINATION}
+    )
+endif()
+set(qmldir_install_pregen_file
+  "${vtk_qml_module_tmp_install_path}/qmldir.install.pregen")
+configure_file(
+  "${CMAKE_CURRENT_SOURCE_DIR}/qmldir.in"
+  "${qmldir_install_pregen_file}"
+  @ONLY
+  )
+set(qmldir_install_gen_file
+  "${vtk_qml_module_install_path}/qmldir")
+file(GENERATE OUTPUT ${qmldir_install_gen_file}
+  INPUT ${qmldir_install_pregen_file})
+
+install(FILES ${qmltypes_file}
+  DESTINATION ${vtk_qml_module_install_path}
+  COMPONENT ${_vtk_build_TARGETS_COMPONENT}
+  )
+
+# Install the QML plugin module
+install(DIRECTORY
+  ${vtk_qml_module_install_path}
+  DESTINATION "${CMAKE_INSTALL_PREFIX}"
+  COMPONENT ${_vtk_build_TARGETS_COMPONENT}
+  )
diff --git a/GUISupport/QtQuick/QQmlVTKPlugin.cxx b/GUISupport/QtQuick/QQmlVTKPlugin.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ad1576552369fce1a897ba939c5172c3731d03bb
--- /dev/null
+++ b/GUISupport/QtQuick/QQmlVTKPlugin.cxx
@@ -0,0 +1,50 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    QQmlVTKPlugin.cxx
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+// vtk includes
+#include "QQmlVTKPlugin.h"
+
+#include "QQuickVTKInteractiveWidget.h"
+#include "QQuickVTKRenderItem.h"
+#include "QQuickVTKRenderWindow.h"
+#include "vtkVersion.h"
+
+// Qt includes
+#include <QQmlEngine>
+
+//-------------------------------------------------------------------------------------------------
+void QQmlVTKPlugin::registerTypes(const char* uri)
+{
+  Q_ASSERT(QString::compare(uri, "VTK") == 0);
+
+  int major = vtkVersion::GetVTKMajorVersion();
+  int minor = vtkVersion::GetVTKMinorVersion();
+
+  // Register QML metatypes
+  qmlRegisterType<QQuickVTKRenderWindow>(uri, major, minor, "VTKRenderWindow");
+  qmlRegisterType<QQuickVTKRenderItem>(uri, major, minor, "VTKRenderItem");
+  qmlRegisterType<QQuickVTKInteractiveWidget>(uri, major, minor, "VTKWidget");
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQmlVTKPlugin::initializeEngine(QQmlEngine* engine, const char* uri)
+{
+  Q_ASSERT(QString::compare(uri, "VTK") == 0);
+
+  QObject::connect(
+    engine, &QQmlEngine::destroyed, this, &QQmlVTKPlugin::cleanup, Qt::DirectConnection);
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQmlVTKPlugin::cleanup() {}
diff --git a/GUISupport/QtQuick/QQmlVTKPlugin.h b/GUISupport/QtQuick/QQmlVTKPlugin.h
new file mode 100644
index 0000000000000000000000000000000000000000..fa3e8cd5d673989101430fe7ca95eb2da295c91a
--- /dev/null
+++ b/GUISupport/QtQuick/QQmlVTKPlugin.h
@@ -0,0 +1,107 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    QQmlVTKPlugin.h
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+#ifndef QQmlVTKPlugin_h
+#define QQmlVTKPlugin_h
+
+// vtk includes
+#include "vtkGUISupportQtQuickModule.h" // for export macro
+
+// Qt includes
+#include <QQmlExtensionPlugin>
+
+// Forward declarations
+
+/**
+ * \class QQmlVTKPlugin
+ * \brief Plugin class to expose a VTK C++ module to QML applications
+ *
+ * QQmlVTKPlugin registers various VTK C++ classes as QML types so that QtQuick applications can
+ * directly import and use these types from QML.
+ *
+ * ## Importing the VTK module in QML
+ * As part of VTK's compilation process, it would compile and install a \em \b qmldir file that
+ * provides the module definition and relevant plugin information required by QML to load VTK. To
+ * load the plugin, set the environment variable
+ * [QML2_IMPORT_PATH](https://doc.qt.io/qt-5/qtqml-syntax-imports.html#qml-import-path) to the path
+ * of the directory containing the \em qmldir file.
+ *
+ *  \code
+ *  # /projects/Import has a sub-directory VTK.9.0/qmldir
+ *  $ export QML2_IMPORT_PATH=/projects/Import
+ *  \endcode
+ *
+ *  Once the import path is set correctly, the module can be imported in the \em .qml file as
+ *  follows:
+ *
+ *  \code
+ *  import VTK 9.0
+ *  \endcode
+ *
+ *  ## Registered types
+ *  The C++ classes exposed to QML and their associated typenames are as follows:
+ *
+ *   | VTK C++ class               |   QML type       |
+ *   | :--------------:            | :--------------: |
+ *   | QQuickVTKRenderWindow       |  VTKRenderWindow |
+ *   | QQuickVTKRenderItem         |  VTKRenderItem   |
+ *   | QQuickVTKInteractiveWidget  |  VTKWidget       |
+ *
+ * ## Versioning
+ * The VTK QML module follows the version number of the VTK source tree. For example, if compiled
+ * against VTK 9.0.x, the VTK module version will be 9.0
+ */
+class VTKGUISUPPORTQTQUICK_EXPORT QQmlVTKPlugin : public QQmlExtensionPlugin
+{
+  Q_OBJECT
+  typedef QQmlExtensionPlugin Superclass;
+
+  Q_PLUGIN_METADATA(IID "org.kitware.VTK")
+
+public:
+  /**
+   * Constructor
+   */
+  QQmlVTKPlugin() = default;
+
+  /**
+   * Destructor
+   */
+  virtual ~QQmlVTKPlugin() = default;
+
+  /**
+   * Register QML types provided by VTK
+   */
+  void registerTypes(const char* uri);
+
+  /**
+   * Initialize the extension using the QQmlEngine
+   *
+   * \sa cleanup
+   */
+  void initializeEngine(QQmlEngine* engine, const char* uri);
+
+protected Q_SLOTS:
+  /**
+   * Destroy any singleton instances that were created during initializeEngine
+   *
+   * \sa initializeEngine
+   */
+  void cleanup();
+
+private:
+  Q_DISABLE_COPY(QQmlVTKPlugin);
+};
+
+#endif // QQmlVTKPlugin_h
diff --git a/GUISupport/QtQuick/QQuickVTKInteractiveWidget.cxx b/GUISupport/QtQuick/QQuickVTKInteractiveWidget.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..1e436d431396496c19296695f921443ae54c8c85
--- /dev/null
+++ b/GUISupport/QtQuick/QQuickVTKInteractiveWidget.cxx
@@ -0,0 +1,73 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    QQuickVTKInteractiveWidget.cxx
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+#include "QQuickVTKInteractiveWidget.h"
+
+// vtk includes
+#include "vtkAbstractWidget.h"
+#include "vtkRenderWindow.h"
+#include "vtkRenderWindowInteractor.h"
+#include "vtkRenderer.h"
+#include "vtkWidgetRepresentation.h"
+
+//-------------------------------------------------------------------------------------------------
+QQuickVTKInteractiveWidget::QQuickVTKInteractiveWidget(QObject* parent)
+  : Superclass(parent)
+{
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKInteractiveWidget::setWidget(vtkAbstractWidget* w)
+{
+  this->m_widget = w;
+}
+
+//-------------------------------------------------------------------------------------------------
+vtkAbstractWidget* QQuickVTKInteractiveWidget::widget() const
+{
+  return this->m_widget;
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKInteractiveWidget::setEnabled(bool e)
+{
+  if (this->m_enabled == e)
+  {
+    return;
+  }
+
+  this->m_enabled = e;
+  Q_EMIT this->enabledChanged(this->m_enabled);
+}
+
+//-------------------------------------------------------------------------------------------------
+bool QQuickVTKInteractiveWidget::enabled() const
+{
+  return this->m_enabled;
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKInteractiveWidget::sync(vtkRenderer* ren)
+{
+  if (!ren || !this->m_widget)
+  {
+    return;
+  }
+
+  auto iren = ren->GetRenderWindow()->GetInteractor();
+  this->m_widget->SetInteractor(iren);
+  this->m_widget->SetCurrentRenderer(ren);
+  this->m_widget->SetEnabled(this->m_enabled);
+  this->m_widget->SetProcessEvents(this->m_enabled);
+}
diff --git a/GUISupport/QtQuick/QQuickVTKInteractiveWidget.h b/GUISupport/QtQuick/QQuickVTKInteractiveWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..ba017a04aed8ae3ae5a2e7475307363ac6aaef41
--- /dev/null
+++ b/GUISupport/QtQuick/QQuickVTKInteractiveWidget.h
@@ -0,0 +1,83 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    QQuickVTKInteractiveWidget.h
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+/**
+ * @class QQuickVTKInteractiveWidget
+ * @brief QObject that manages a VTK interactive widget to ensure that it behaves as per the QtQuick
+ * threaded render loop.
+ *
+ * QQuickVTKInteractiveWidget holds a weak reference to the vtk widget it manages.
+ */
+
+#ifndef QQuickVTKInteractiveWidget_h
+#define QQuickVTKInteractiveWidget_h
+
+// Qt includes
+#include <QObject>
+
+// vtk includes
+#include "vtkWeakPointer.h" // For vtkWeakPointer
+
+#include "vtkGUISupportQtQuickModule.h" // for export macro
+
+// Forward declarations
+class vtkAbstractWidget;
+class vtkRenderer;
+
+class VTKGUISUPPORTQTQUICK_EXPORT QQuickVTKInteractiveWidget : public QObject
+{
+  Q_OBJECT
+  typedef QObject Superclass;
+
+  Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged);
+
+public:
+  QQuickVTKInteractiveWidget(QObject* parent = nullptr);
+  ~QQuickVTKInteractiveWidget() = default;
+
+  ///@{
+  /**
+   * Set/Get the widget reference
+   */
+  void setWidget(vtkAbstractWidget* w);
+  vtkAbstractWidget* widget() const;
+  ///@}
+
+  ///@{
+  /**
+   * Set/Get whether the widget is enabled.
+   */
+  void setEnabled(bool e);
+  bool enabled() const;
+  ///@}
+
+public Q_SLOTS:
+  virtual void sync(vtkRenderer* ren);
+
+Q_SIGNALS:
+  void enabledChanged(bool e);
+
+protected:
+  // Helper members
+  vtkWeakPointer<vtkAbstractWidget> m_widget;
+
+  // Enabled/disabled
+  bool m_enabled = false;
+
+private:
+  QQuickVTKInteractiveWidget(const QQuickVTKInteractiveWidget&) = delete;
+  void operator=(const QQuickVTKInteractiveWidget) = delete;
+};
+
+#endif // QQuickVTKInteractiveWidget_h
diff --git a/GUISupport/QtQuick/QQuickVTKInteractorAdapter.cxx b/GUISupport/QtQuick/QQuickVTKInteractorAdapter.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..b0cc346d3420118d87003539c7126fe8f4fa6a6e
--- /dev/null
+++ b/GUISupport/QtQuick/QQuickVTKInteractorAdapter.cxx
@@ -0,0 +1,128 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    QQuickVTKInteractorAdapter.cxx
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+#include "QQuickVTKInteractorAdapter.h"
+
+// Qt includes
+#include <QEvent>
+#include <QQuickItem>
+#include <QQuickWindow>
+
+// VTK includes
+#include "vtkRenderWindowInteractor.h"
+
+//-------------------------------------------------------------------------------------------------
+QQuickVTKInteractorAdapter::QQuickVTKInteractorAdapter(QObject* parent)
+  : Superclass(parent)
+{
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKInteractorAdapter::setQQuickWindow(QQuickWindow* win)
+{
+  m_qwindow = win;
+}
+
+//-------------------------------------------------------------------------------------------------
+QPointF QQuickVTKInteractorAdapter::mapEventPosition(QQuickItem* item, const QPointF& localPos)
+{
+  // Account for the difference in coordinate reference systems.
+  // Qt uses quadrant IV and VTK uses quadrant I. So the point should be
+  // translated to the right position along Y axis.
+  return item->mapToScene(localPos);
+}
+
+//-------------------------------------------------------------------------------------------------
+QPointF QQuickVTKInteractorAdapter::mapEventPositionFlipY(QQuickItem* item, const QPointF& localPos)
+{
+  QPointF mappedPos = QQuickVTKInteractorAdapter::mapEventPosition(item, localPos);
+  mappedPos.setY(item->window()->height() - mappedPos.y() + 1);
+  return mappedPos;
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKInteractorAdapter::QueueHoverEvent(QQuickItem* item, QHoverEvent* e)
+{
+  QHoverEvent* newEvent = new QHoverEvent(e->type(), this->mapEventPosition(item, e->posF()),
+    this->mapEventPosition(item, e->oldPosF()), e->modifiers());
+  QueueEvent(newEvent);
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKInteractorAdapter::QueueKeyEvent(QQuickItem* item, QKeyEvent* e)
+{
+  Q_UNUSED(item);
+  QKeyEvent* newEvent = new QKeyEvent(e->type(), e->key(), e->modifiers(), e->nativeScanCode(),
+    e->nativeVirtualKey(), e->nativeModifiers(), e->text(), e->isAutoRepeat(), e->count());
+  QueueEvent(newEvent);
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKInteractorAdapter::QueueFocusEvent(QQuickItem* item, QFocusEvent* e)
+{
+  Q_UNUSED(item);
+  QFocusEvent* newEvent = new QFocusEvent(e->type(), e->reason());
+  QueueEvent(newEvent);
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKInteractorAdapter::QueueMouseEvent(QQuickItem* item, QMouseEvent* e)
+{
+  QMouseEvent* newEvent = new QMouseEvent(e->type(), this->mapEventPosition(item, e->localPos()),
+    this->mapEventPosition(item, e->windowPos()), this->mapEventPosition(item, e->screenPos()),
+    e->button(), e->buttons(), e->modifiers());
+  QueueEvent(newEvent);
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKInteractorAdapter::QueueGeometryChanged(
+  const QRectF& newGeometry, const QRectF& oldGeometry)
+{
+  QResizeEvent* newEvent =
+    new QResizeEvent(newGeometry.size().toSize(), oldGeometry.size().toSize());
+  QueueEvent(newEvent);
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKInteractorAdapter::QueueWheelEvent(QQuickItem* item, QWheelEvent* e)
+{
+  QWheelEvent* newEvent = new QWheelEvent(this->mapEventPosition(item, e->position()),
+    this->mapEventPosition(item, e->globalPosition()), e->pixelDelta(), e->angleDelta(),
+    e->buttons(), e->modifiers(), e->phase(), e->inverted(), e->source());
+  QueueEvent(newEvent);
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKInteractorAdapter::QueueEvent(QEvent* e)
+{
+  m_queuedEvents << e;
+  if (m_qwindow)
+  {
+    m_qwindow->update();
+  }
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKInteractorAdapter::ProcessEvents(vtkRenderWindowInteractor* interactor)
+{
+  if (interactor)
+  {
+    for (QEvent* e : this->m_queuedEvents)
+    {
+      ProcessEvent(e, interactor);
+    }
+    qDeleteAll(m_queuedEvents);
+    m_queuedEvents.clear();
+  }
+}
diff --git a/GUISupport/QtQuick/QQuickVTKInteractorAdapter.h b/GUISupport/QtQuick/QQuickVTKInteractorAdapter.h
new file mode 100644
index 0000000000000000000000000000000000000000..a21126a677eb6311a8a28b61187c19ce3eace129
--- /dev/null
+++ b/GUISupport/QtQuick/QQuickVTKInteractorAdapter.h
@@ -0,0 +1,92 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    QQuickVTKInteractorAdapter.h
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+#ifndef QQuickVTKInteractorAdapter_h
+#define QQuickVTKInteractorAdapter_h
+
+// VTK includes
+#include "QVTKInteractorAdapter.h"
+#include "vtkGUISupportQtQuickModule.h" // for export macro
+
+// Qt includes
+#include <QList>    // for QList
+#include <QPointer> // for QPointer
+
+// Forward declarations
+class QEnterEvent;
+class QEvent;
+class QFocusEvent;
+class QHoverEvent;
+class QKeyEvent;
+class QMouseEvent;
+class QQuickItem;
+class QQuickWindow;
+class QWheelEvent;
+class vtkRenderWindowInteractor;
+class vtkRenderer;
+
+/**
+ * @class QQuickVTKInteractorAdapter
+ * @brief Intermediate class that handles relaying Qt events to VTK
+ */
+class VTKGUISUPPORTQTQUICK_EXPORT QQuickVTKInteractorAdapter : public QVTKInteractorAdapter
+{
+  Q_OBJECT
+  typedef QVTKInteractorAdapter Superclass;
+
+public:
+  QQuickVTKInteractorAdapter(QObject* parent = nullptr);
+
+  void setQQuickWindow(QQuickWindow* win);
+
+  void QueueHoverEvent(QQuickItem* item, QHoverEvent* e);
+  void QueueKeyEvent(QQuickItem* item, QKeyEvent* e);
+  void QueueFocusEvent(QQuickItem* item, QFocusEvent* e);
+  void QueueMouseEvent(QQuickItem* item, QMouseEvent* e);
+  void QueueGeometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry);
+  void QueueWheelEvent(QQuickItem* item, QWheelEvent* e);
+
+  void ProcessEvents(vtkRenderWindowInteractor* interactor);
+
+  /*
+   * Map the event position to VTK display coordinates
+   * The mapping considers the following:
+   *  - VTK widgets expect display coordinates, not viewport/local coordinates
+   *  - vtkRenderWindowInteractor flips Y before processing the event.
+   * Because of the inherent flip in the superclass, the mapping does not flip Y implicitly.
+   * To map and flip Y, use mapEventPositionFlipY.
+   *
+   * \sa mapEventPositionFlipY
+   */
+  static QPointF mapEventPosition(QQuickItem* item, const QPointF& localPos);
+
+  /*
+   * Map the event position to VTK display coordinates and flip the Y axis to switch the point from
+   * the Qt coordinate reference system to VTK's.
+   *
+   * \sa mapEventPosition
+   */
+  static QPointF mapEventPositionFlipY(QQuickItem* item, const QPointF& localPos);
+
+protected:
+  void QueueEvent(QEvent* e);
+
+private:
+  QPointer<QQuickWindow> m_qwindow;
+  QList<QEvent*> m_queuedEvents;
+
+  Q_DISABLE_COPY(QQuickVTKInteractorAdapter)
+};
+
+#endif // QQuickVTKInteractorAdapter_h
diff --git a/GUISupport/QtQuick/QQuickVTKRenderItem.cxx b/GUISupport/QtQuick/QQuickVTKRenderItem.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..1ac3d32ed5da4ce413e2857d45f43ed324130675
--- /dev/null
+++ b/GUISupport/QtQuick/QQuickVTKRenderItem.cxx
@@ -0,0 +1,290 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    QQuickVTKRenderItem.cxx
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+#include "QQuickVTKRenderItem.h"
+
+// vtk includes
+#include "QQuickVTKInteractiveWidget.h"
+#include "QQuickVTKInteractorAdapter.h"
+#include "QQuickVTKRenderWindow.h"
+#include "vtkImageData.h"
+#include "vtkRenderWindow.h"
+
+// Qt includes
+#include <QQuickWindow>
+
+//-------------------------------------------------------------------------------------------------
+QQuickVTKRenderItem::QQuickVTKRenderItem(QQuickItem* parent)
+  : Superclass(parent)
+{
+  // Accept mouse events
+  setAcceptHoverEvents(true);
+  setAcceptedMouseButtons(Qt::AllButtons);
+  setFlag(QQuickItem::ItemIsFocusScope);
+  setFlag(QQuickItem::ItemHasContents);
+
+  QObject::connect(
+    this, &QQuickItem::windowChanged, this, &QQuickVTKRenderItem::handleWindowChanged);
+}
+
+//-------------------------------------------------------------------------------------------------
+QQuickVTKRenderWindow* QQuickVTKRenderItem::renderWindow() const
+{
+  return this->m_renderWindow;
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderItem::setRenderWindow(QQuickVTKRenderWindow* w)
+{
+  if (this->m_renderWindow == w)
+  {
+    return;
+  }
+
+  if (this->m_renderWindow)
+  {
+    this->m_renderWindow->renderWindow()->RemoveRenderer(this->m_renderer);
+  }
+
+  this->m_renderWindow = w;
+  if (this->m_renderWindow && this->m_renderWindow->renderWindow())
+  {
+    this->m_renderWindow->renderWindow()->AddRenderer(this->m_renderer);
+  }
+
+  this->m_renderWindow->render();
+}
+
+//-------------------------------------------------------------------------------------------------
+vtkRenderer* QQuickVTKRenderItem::renderer() const
+{
+  return this->m_renderer;
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderItem::setViewport(const QRectF& rect)
+{
+  if (!this->m_renderWindow)
+  {
+    return;
+  }
+  double viewport[4];
+  this->m_renderWindow->mapToViewport(rect, viewport);
+  m_renderer->SetViewport(viewport);
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderItem::sync()
+{
+  if (!this->isVisible())
+  {
+    return;
+  }
+
+  if (!this->m_renderWindow)
+  {
+    return;
+  }
+
+  // Forward the synchronize call to the window
+  this->m_renderWindow->sync();
+
+  // Explicitly set the viewport for each render window
+  // This is done after the window sync to ensure that the window size is set up.
+  QRectF rect(0, 0, this->width(), this->height());
+  rect = this->mapRectToScene(rect);
+  this->setViewport(rect);
+
+  // Now synchronize all the widgets
+  for (auto it = this->m_widgets.constBegin(); it < this->m_widgets.constEnd(); ++it)
+  {
+    (*it)->sync(this->renderer());
+  }
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderItem::paint()
+{
+  if (!this->isVisible())
+  {
+    return;
+  }
+  if (!this->m_renderWindow)
+  {
+    return;
+  }
+
+  // Forward the paint call to the window
+  this->m_renderWindow->paint();
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderItem::cleanup()
+{
+  if (!this->isVisible())
+  {
+    return;
+  }
+  if (!this->m_renderWindow)
+  {
+    return;
+  }
+
+  this->m_renderer->ReleaseGraphicsResources(this->m_renderWindow->renderWindow());
+  // Forward the cleanup call to the window
+  this->m_renderWindow->cleanup();
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderItem::handleWindowChanged(QQuickWindow* w)
+{
+  if (this->window())
+  {
+    QObject::disconnect(
+      this->window(), &QQuickWindow::beforeSynchronizing, this, &QQuickVTKRenderItem::sync);
+    QObject::disconnect(
+      window(), &QQuickWindow::beforeRendering, this, &QQuickVTKRenderItem::paint);
+    QObject::disconnect(
+      window(), &QQuickWindow::sceneGraphInvalidated, this, &QQuickVTKRenderItem::cleanup);
+  }
+
+  if (w)
+  {
+    QObject::connect(w, &QQuickWindow::beforeSynchronizing, this, &QQuickVTKRenderItem::sync,
+      Qt::DirectConnection);
+    QObject::connect(
+      w, &QQuickWindow::beforeRendering, this, &QQuickVTKRenderItem::paint, Qt::DirectConnection);
+    QObject::connect(w, &QQuickWindow::sceneGraphInvalidated, this, &QQuickVTKRenderItem::cleanup,
+      Qt::DirectConnection);
+  }
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderItem::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
+{
+  if (!this->renderWindow())
+  {
+    return;
+  }
+  this->renderWindow()->interactorAdapter()->QueueGeometryChanged(newGeometry, oldGeometry);
+
+  Superclass::geometryChanged(newGeometry, oldGeometry);
+}
+
+//-------------------------------------------------------------------------------------------------
+bool QQuickVTKRenderItem::event(QEvent* ev)
+{
+  if (!ev)
+  {
+    return false;
+  }
+
+  switch (ev->type())
+  {
+    case QEvent::HoverEnter:
+    case QEvent::HoverLeave:
+    case QEvent::HoverMove:
+    {
+      this->renderWindow()->interactorAdapter()->QueueHoverEvent(
+        this, static_cast<QHoverEvent*>(ev));
+      break;
+    }
+    case QEvent::KeyPress:
+    case QEvent::KeyRelease:
+    {
+      this->renderWindow()->interactorAdapter()->QueueKeyEvent(this, static_cast<QKeyEvent*>(ev));
+      break;
+    }
+    case QEvent::FocusIn:
+    case QEvent::FocusOut:
+    {
+      this->renderWindow()->interactorAdapter()->QueueFocusEvent(
+        this, static_cast<QFocusEvent*>(ev));
+      break;
+    }
+    case QEvent::MouseMove:
+    case QEvent::MouseButtonPress:
+    case QEvent::MouseButtonRelease:
+    case QEvent::MouseButtonDblClick:
+    {
+      this->renderWindow()->interactorAdapter()->QueueMouseEvent(
+        this, static_cast<QMouseEvent*>(ev));
+      break;
+    }
+#ifndef QT_NO_WHEELEVENT
+    case QEvent::Wheel:
+    {
+      this->renderWindow()->interactorAdapter()->QueueWheelEvent(
+        this, static_cast<QWheelEvent*>(ev));
+      break;
+    }
+#endif
+    default:
+    {
+      return this->Superclass::event(ev);
+    }
+  }
+
+  ev->accept();
+  return true;
+}
+
+//-------------------------------------------------------------------------------------------------
+vtkSmartPointer<vtkImageData> QQuickVTKRenderItem::captureScreenshot()
+{
+  if (!this->renderWindow())
+  {
+    return nullptr;
+  }
+  return this->renderWindow()->captureScreenshot(this->m_renderer->GetViewport());
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderItem::addWidget(QQuickVTKInteractiveWidget* w)
+{
+  this->m_widgets.push_back(w);
+  this->update();
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderItem::removeWidget(QQuickVTKInteractiveWidget* w)
+{
+  this->m_widgets.removeOne(w);
+  this->update();
+}
+
+//-------------------------------------------------------------------------------------------------
+QQuickVTKInteractiveWidget* QQuickVTKRenderItem::widgetByName(QString name) const
+{
+  for (auto it = this->m_widgets.constBegin(); it < this->m_widgets.constEnd(); ++it)
+  {
+    if ((*it)->objectName().compare(name) == 0)
+    {
+      return (*it);
+    }
+  }
+  return nullptr;
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderItem::removeWidgetByName(QString name)
+{
+  auto w = this->widgetByName(name);
+  if (!w)
+  {
+    return;
+  }
+
+  this->removeWidget(w);
+}
diff --git a/GUISupport/QtQuick/QQuickVTKRenderItem.h b/GUISupport/QtQuick/QQuickVTKRenderItem.h
new file mode 100644
index 0000000000000000000000000000000000000000..e139cbfbe1c4b496e9727047528c5efe494c364a
--- /dev/null
+++ b/GUISupport/QtQuick/QQuickVTKRenderItem.h
@@ -0,0 +1,244 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    QQuickVTKRenderItem.h
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+/**
+ * @class QQuickVTKRenderItem
+ * @brief [QQuickItem] subclass to render a VTK scene in a QtQuick/QML application.
+ *
+ * QQuickVTKRenderItem extends [QQuickItem] so that a VTK visualization pipeline can be rendererd
+ * within the rect of the item.
+ *
+ * This item is exported to the QML layer via the QQmlVTKPlugin under the module VTK. It is
+ * registered as a type \b VTKRenderItem. The QQuickVTKRenderItem manages a vtkRenderer internally
+ * that is rendered as a viewport inside the render window provided by QQuickVTKRenderWindow.
+ *
+ * Typical usage for QQuickVTKRenderItem in a Qml application is as follows:
+ *
+ * @code
+ *  // import related modules
+ *  import QtQuick 2.15
+ *  import QtQuick.Controls 2.15
+ *  import QtQuick.Window 2.15
+ *
+ *  // import the VTK module
+ *  import VTK 9.0
+ *
+ *  // window containing the application
+ *  ApplicationWindow {
+ *    // title of the application
+ *    title: qsTr("VTK QtQuick App")
+ *    width: 400
+ *    height: 400
+ *    color: palette.window
+ *
+ *    SystemPalette {
+ *      id: palette
+ *      colorGroup: SystemPalette.Active
+ *    }
+ *
+ *    // Instantiate the vtk render window
+ *    VTKRenderWindow {
+ *      id: vtkwindow
+ *      width: 400
+ *      height: 400
+ *    }
+ *
+ *    // add one or more vtk render items
+ *    VTKRenderItem {
+ *      objectName: "ConeView"
+ *      x: 200
+ *      y: 200
+ *      width: 200
+ *      height: 200
+ *      // Provide the handle to the render window
+ *      renderWindow: vtkwindow
+ *    }
+ *  }
+ * @endcode
+ *
+ * The corresponding C++ class that sets up the VTK pipeline would look like the following:
+ *
+ * @code
+ *   QQmlApplicaQtionEngine engine;
+ *   engine.load(QUrl("qrc:///<qmlfile>.qml"));
+ *
+ *   QObject* topLevel = engine.rootObjects().value(0);
+ *   QQuickWindow* window = qobject_cast<QQuickWindow*>(topLevel);
+ *
+ *   window->show();
+ *
+ *   // Fetch the QQuick window using the standard object name set up in the constructor
+ *   QQuickVTKRenderItem* qquickvtkItem = topLevel->findChild<QQuickVTKRenderItem*>("ConeView");
+ *
+ *   // Create a cone pipeline and add it to the view
+ *   vtkNew<vtkActor> actor;
+ *   vtkNew<vtkPolyDataMapper> mapper;
+ *   vtkNew<vtkConeSource> cone;
+ *   mapper->SetInputConnection(cone->GetOutputPort());
+ *   actor->SetMapper(mapper);
+ *   qquickvtkItem->renderer()->AddActor(actor);
+ *   qquickvtkItem->renderer()->ResetCamera();
+ *   qquickvtkItem->renderer()->SetBackground(0.5, 0.5, 0.7);
+ *   qquickvtkItem->renderer()->SetBackground2(0.7, 0.7, 0.7);
+ *   qquickvtkItem->renderer()->SetGradientBackground(true);
+ *   qquickvtkItem->update();
+ * @endcode
+ *
+ * ## QtQuick scenegraph and threaded render loop
+ *
+ * QtQuick/QML scenegraph rendering is done via private API inside the [QQuickWindow] class. For
+ * details on QtQuick's render loop, see [QtQuick Scenegraph Rendering](
+ * https://doc.qt.io/qt-6/qtquick-visualcanvas-scenegraph.html#scene-graph-and-rendering).
+ * Qt automatically decides between a threaded and basic render loop for most applications.
+ * QQuickVTKRenderWindow and QQuickVTKRenderItem support both these variants of the QtQuick render
+ * loop.
+ *
+ * When the scenegraph render loop is threaded, i.e. there is a dedicated rendering thread, vtk
+ * sticks to doing all rendering on this render thread. This means that all the vtk classes,
+ * pipelines etc. can be set up on the main thread but vtkRenderWindow::Render should only be
+ * invoked on the render thread. Care must be taken not to call Render on the main thread because
+ * the OpenGL context would not be valid on the main thread.
+ *
+ * ## Interactive vtk widgets
+ *
+ * QQuickVTKRenderItem also supports interactive vtk widgets with QtQuick's threaded render loop via
+ * the QQuickVTKInteractiveWidget class.
+ *
+ * [QQuickItem]: https://doc.qt.io/qt-5/qquickitem.html
+ * [QQuickWindow]: https://doc.qt.io/qt-5/qquickwindow.html
+ */
+
+#ifndef QQuickVTKRenderItem_h
+#define QQuickVTKRenderItem_h
+
+// Qt includes
+#include <QOpenGLFunctions> // For QOpenGLFunctions
+#include <QQuickItem>
+
+// vtk includes
+#include "vtkNew.h"      // For vtkNew
+#include "vtkRenderer.h" // For vtkRenderer
+
+#include "vtkGUISupportQtQuickModule.h" // for export macro
+
+// Forward declarations
+class QHoverEvent;
+class QKeyEvent;
+class QMouseEvent;
+class QQuickVTKInteractiveWidget;
+class QQuickVTKRenderWindow;
+class vtkImageData;
+
+class VTKGUISUPPORTQTQUICK_EXPORT QQuickVTKRenderItem
+  : public QQuickItem
+  , protected QOpenGLFunctions
+{
+  Q_OBJECT
+  typedef QQuickItem Superclass;
+
+  Q_PROPERTY(QQuickVTKRenderWindow* renderWindow READ renderWindow WRITE setRenderWindow)
+
+public:
+  QQuickVTKRenderItem(QQuickItem* parent = nullptr);
+  ~QQuickVTKRenderItem() = default;
+
+  ///@{
+  /**
+   * Set/Get the render window for the item
+   */
+  QQuickVTKRenderWindow* renderWindow() const;
+  virtual void setRenderWindow(QQuickVTKRenderWindow* w);
+  ///@}
+
+  /**
+   * Get access to the renderer
+   */
+  vtkRenderer* renderer() const;
+
+  /**
+   * Capture a screenshot of the view
+   *
+   * \returns Image data containing the view capture.
+   * \sa QQuickVTKRenderWindow::captureScreenshot
+   */
+  virtual vtkSmartPointer<vtkImageData> captureScreenshot();
+
+  ///@{
+  /**
+   * Add/Remove widgets to/from the view
+   */
+  virtual void addWidget(QQuickVTKInteractiveWidget* w);
+  virtual void removeWidget(QQuickVTKInteractiveWidget* w);
+  ///@}
+
+  ///@{
+  /**
+   * Get/Remove widgets from the view by their object name
+   */
+  virtual QQuickVTKInteractiveWidget* widgetByName(QString name) const;
+  virtual void removeWidgetByName(QString name);
+  ///@}
+
+public Q_SLOTS:
+  /**
+   * This is the function called on the QtQuick render thread before the scenegraph state
+   * is synchronized. This is where most of the pipeline updates, camera manipulations, etc. and
+   * other pre-render steps can be performed.
+   *
+   * \note At the time of this method execution, the GUI thread is blocked. Hence, it is safe to
+   * perform state synchronization between the GUI elements and the VTK classes here.
+   */
+  virtual void sync();
+
+  /**
+   * This is the function called on the QtQuick render thread right before the scenegraph is
+   * rendered. This is the stage where all the vtk rendering is performed. Applications would rarely
+   * need to override this method.
+   *
+   * \note This method is called at the beforeRendering stage of the QtQuick scenegraph. All the
+   * QtQuick element rendering is stacked visually above the vtk rendering.
+   */
+  virtual void paint();
+
+  /**
+   * This is the function called on the QtQuick render thread when the scenegraph is invalidated.
+   * This is where all graphics resources allocated by vtk are released.
+   */
+  virtual void cleanup();
+
+protected Q_SLOTS:
+  virtual void handleWindowChanged(QQuickWindow* w);
+
+protected:
+  // Helper members
+  QQuickVTKRenderWindow* m_renderWindow = nullptr;
+  vtkNew<vtkRenderer> m_renderer;
+
+  QVector<QQuickVTKInteractiveWidget*> m_widgets;
+
+  /**
+   * Set the viewport for this item
+   */
+  virtual void setViewport(const QRectF& rect);
+
+  // Event handlers
+  void geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry) override;
+  bool event(QEvent* ev) override;
+
+private:
+  QQuickVTKRenderItem(const QQuickVTKRenderItem&) = delete;
+  void operator=(const QQuickVTKRenderItem) = delete;
+};
+
+#endif // QQuickVTKRenderItem_h
diff --git a/GUISupport/QtQuick/QQuickVTKRenderWindow.cxx b/GUISupport/QtQuick/QQuickVTKRenderWindow.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..4280858189ba2b98d80b749f93b937ab3e079fbf
--- /dev/null
+++ b/GUISupport/QtQuick/QQuickVTKRenderWindow.cxx
@@ -0,0 +1,299 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    QQuickVTKRenderWindow.cxx
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+#include "QQuickVTKRenderWindow.h"
+
+// vtk includes
+#include "QQuickVTKInteractorAdapter.h"
+#include "QVTKInteractor.h"
+#include "vtkGenericOpenGLRenderWindow.h"
+#include "vtkImageData.h"
+#include "vtkInteractorStyleTrackballCamera.h"
+#include "vtkOpenGLState.h"
+#include "vtkRenderWindowInteractor.h"
+#include "vtkWindowToImageFilter.h"
+
+// Qt includes
+#include <QQuickWindow>
+
+//-------------------------------------------------------------------------------------------------
+QQuickVTKRenderWindow::QQuickVTKRenderWindow(QQuickItem* parent)
+  : Superclass(parent)
+{
+  vtkNew<vtkGenericOpenGLRenderWindow> renWin;
+  this->setRenderWindow(renWin);
+  this->m_interactorAdapter = new QQuickVTKInteractorAdapter(this);
+  QObject::connect(
+    this, &QQuickItem::windowChanged, this, &QQuickVTKRenderWindow::handleWindowChanged);
+
+  // Set a standard object name
+  this->setObjectName("QQuickVTKRenderWindow");
+}
+
+//-------------------------------------------------------------------------------------------------
+QQuickVTKRenderWindow::~QQuickVTKRenderWindow()
+{
+  this->m_renderWindow = nullptr;
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderWindow::sync()
+{
+  if (!this->isVisible())
+  {
+    return;
+  }
+
+  if (!this->m_renderWindow)
+  {
+    return;
+  }
+
+  QSize windowSize = window()->size() * window()->devicePixelRatio();
+  this->m_renderWindow->SetSize(windowSize.width(), windowSize.height());
+  if (auto iren = this->m_renderWindow->GetInteractor())
+  {
+    iren->SetSize(windowSize.width(), windowSize.height());
+    m_interactorAdapter->ProcessEvents(iren);
+  }
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderWindow::paint()
+{
+  if (!this->isVisible())
+  {
+    return;
+  }
+
+  if (!this->m_renderWindow)
+  {
+    // no render window set, just fill with white.
+    QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions();
+    f->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+    f->glClear(GL_COLOR_BUFFER_BIT);
+    return;
+  }
+
+  auto iren = this->m_renderWindow->GetInteractor();
+  if (!this->m_initialized)
+  {
+    initializeOpenGLFunctions();
+    if (iren)
+    {
+      iren->Initialize();
+    }
+    this->m_renderWindow->SetMapped(true);
+    this->m_renderWindow->SetIsCurrent(true);
+
+    // Since the context is being setup, call OpenGLInitContext
+    this->m_renderWindow->SetForceMaximumHardwareLineWidth(1);
+    this->m_renderWindow->SetOwnContext(true);
+    this->m_renderWindow->OpenGLInitContext();
+
+    m_initialized = true;
+  }
+
+  auto ostate = this->m_renderWindow->GetState();
+  ostate->Reset();
+  ostate->Push();
+  // By default, Qt sets the depth function to GL_LESS but VTK expects GL_LEQUAL
+  ostate->vtkglDepthFunc(GL_LEQUAL);
+
+  this->m_renderWindow->SetReadyForRendering(true);
+  if (iren)
+  {
+    iren->Render();
+  }
+  else
+  {
+    this->m_renderWindow->Render();
+  }
+
+  if (this->m_screenshotScheduled)
+  {
+    this->m_screenshotFilter->SetInput(this->m_renderWindow);
+    this->m_screenshotFilter->SetReadFrontBuffer(false);
+    this->m_screenshotFilter->SetInputBufferTypeToRGB();
+    this->m_screenshotFilter->Update();
+    this->m_screenshotScheduled = false;
+  }
+  this->m_renderWindow->SetReadyForRendering(false);
+
+  ostate->Pop();
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderWindow::cleanup()
+{
+  if (this->m_renderWindow)
+  {
+    this->m_renderWindow->ReleaseGraphicsResources(this->m_renderWindow);
+  }
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderWindow::handleWindowChanged(QQuickWindow* w)
+{
+  this->m_interactorAdapter->setQQuickWindow(w);
+  if (w)
+  {
+    // Do not clear the scenegraph before the QML rendering
+    // to preserve the VTK render
+    w->setClearBeforeRendering(false);
+    // This allows the cleanup method to be called on the render thread
+    w->setPersistentSceneGraph(false);
+  }
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderWindow::setRenderWindow(vtkRenderWindow* renWin)
+{
+  auto gwin = vtkGenericOpenGLRenderWindow::SafeDownCast(renWin);
+  if (renWin != nullptr && gwin == nullptr)
+  {
+    qDebug() << "QQuickVTKRenderWindow requires a `vtkGenericOpenGLRenderWindow`. `"
+             << renWin->GetClassName() << "` is not supported.";
+  }
+  this->setRenderWindow(gwin);
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderWindow::setRenderWindow(vtkGenericOpenGLRenderWindow* renWin)
+{
+  if (this->m_renderWindow == renWin)
+  {
+    return;
+  }
+
+  this->m_renderWindow = renWin;
+  this->m_initialized = false;
+
+  if (this->m_renderWindow)
+  {
+    this->m_renderWindow->SetMultiSamples(0);
+    this->m_renderWindow->SetReadyForRendering(false);
+    this->m_renderWindow->SetFrameBlitModeToBlitToHardware();
+    vtkNew<QVTKInteractor> iren;
+    iren->SetRenderWindow(this->m_renderWindow);
+
+    // now set the default style
+    vtkNew<vtkInteractorStyleTrackballCamera> style;
+    iren->SetInteractorStyle(style);
+
+    this->m_renderWindow->SetReadyForRendering(false);
+  }
+}
+
+//-------------------------------------------------------------------------------------------------
+vtkRenderWindow* QQuickVTKRenderWindow::renderWindow() const
+{
+  return this->m_renderWindow;
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderWindow::mapToViewport(const QRectF& rect, double viewport[4])
+{
+  viewport[0] = rect.topLeft().x();
+  viewport[1] = rect.topLeft().y();
+  viewport[2] = rect.bottomRight().x();
+  viewport[3] = rect.bottomRight().y();
+
+  if (this->m_renderWindow)
+  {
+    int* windowSize = this->m_renderWindow->GetSize();
+    if (windowSize && windowSize[0] != 0 && windowSize[1] != 0)
+    {
+      viewport[0] = viewport[0] / (windowSize[0] - 1.0);
+      viewport[1] = viewport[1] / (windowSize[1] - 1.0);
+      viewport[2] = viewport[2] / (windowSize[0] - 1.0);
+      viewport[3] = viewport[3] / (windowSize[1] - 1.0);
+    }
+  }
+
+  // Change to quadrant I (vtk) from IV (Qt)
+  double tmp = 1.0 - viewport[1];
+  viewport[1] = 1.0 - viewport[3];
+  viewport[3] = tmp;
+
+  for (int i = 0; i < 3; ++i)
+  {
+    viewport[i] = viewport[i] > 0.0 ? viewport[i] : 0.0;
+    viewport[i] = viewport[i] > 1.0 ? 1.0 : viewport[i];
+  }
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderWindow::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
+{
+  m_interactorAdapter->QueueGeometryChanged(newGeometry, oldGeometry);
+
+  Superclass::geometryChanged(newGeometry, oldGeometry);
+}
+
+//-------------------------------------------------------------------------------------------------
+QPointer<QQuickVTKInteractorAdapter> QQuickVTKRenderWindow::interactorAdapter() const
+{
+  return this->m_interactorAdapter;
+}
+
+//-------------------------------------------------------------------------------------------------
+vtkSmartPointer<vtkImageData> QQuickVTKRenderWindow::captureScreenshot()
+{
+  double viewport[4] = { 0, 0, 1, 1 };
+  return this->captureScreenshot(viewport);
+}
+
+//-------------------------------------------------------------------------------------------------
+vtkSmartPointer<vtkImageData> QQuickVTKRenderWindow::captureScreenshot(double* viewport)
+{
+  if (!this->window())
+  {
+    return nullptr;
+  }
+  this->m_screenshotScheduled = true;
+  this->m_screenshotFilter->SetViewport(viewport);
+  this->renderNow();
+  return this->m_screenshotFilter->GetOutput();
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderWindow::renderNow()
+{
+  if (!this->window())
+  {
+    return;
+  }
+  // Schedule a scenegraph update
+  this->window()->update();
+  // Wait for the update to complete
+  QEventLoop loop;
+  QObject::connect(this->window(), &QQuickWindow::afterRendering, &loop, &QEventLoop::quit);
+  loop.exec();
+}
+
+//-------------------------------------------------------------------------------------------------
+void QQuickVTKRenderWindow::render()
+{
+  if (this->window())
+  {
+    this->window()->update();
+  }
+}
+
+//-------------------------------------------------------------------------------------------------
+bool QQuickVTKRenderWindow::isInitialized() const
+{
+  return this->m_initialized;
+}
diff --git a/GUISupport/QtQuick/QQuickVTKRenderWindow.h b/GUISupport/QtQuick/QQuickVTKRenderWindow.h
new file mode 100644
index 0000000000000000000000000000000000000000..a0922b76a2bb1882f81382fbd61c15060db03e6a
--- /dev/null
+++ b/GUISupport/QtQuick/QQuickVTKRenderWindow.h
@@ -0,0 +1,251 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    QQuickVTKRenderWindow.h
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+/**
+ * @class QQuickVTKRenderWindow
+ * @brief [QQuickItem] subclass that manages the vtkRenderWindow and, in
+ * turn, the OpenGL context of the QML application
+ *
+ * QQuickVTKRenderWindow extends [QQuickItem] in a way that allows for VTK to get a handle to, and
+ * draw inside of the QtQuick scenegraph, using OpenGL draw calls.
+ *
+ * This item is exported to the QML layer via the QQmlVTKPlugin under the module VTK. It is
+ * registered as a type \b VTKRenderWindow. Since, this class is intended to manage an OpenGL
+ * context in the window, a single instance would be needed for most QML applications.
+ *
+ * Typical usage for QQuickVTKRenderWindow in a Qml application is as follows:
+ *
+ * @code
+ *  // import related modules
+ *  import QtQuick 2.15
+ *  import QtQuick.Controls 2.15
+ *  import QtQuick.Window 2.15
+ *
+ *  // import the VTK module
+ *  import VTK 9.0
+ *
+ *  // window containing the application
+ *  ApplicationWindow {
+ *    // title of the application
+ *    title: qsTr("VTK QtQuick App")
+ *    width: 400
+ *    height: 400
+ *    color: palette.window
+ *
+ *    SystemPalette {
+ *      id: palette
+ *      colorGroup: SystemPalette.Active
+ *    }
+ *
+ *    // Instantiate the vtk render window
+ *    VTKRenderWindow {
+ *      id: vtkwindow
+ *      width: 400
+ *      height: 400
+ *    }
+ *
+ *    // add one or more vtk render items
+ *    VTKRenderItem {
+ *      objectName: "ConeView"
+ *      x: 200
+ *      y: 200
+ *      width: 200
+ *      height: 200
+ *      // Provide the handle to the render window
+ *      renderWindow: vtkwindow
+ *    }
+ *    VTKRenderItem {
+ *      objectName: "VolumeView"
+ *      x: 0
+ *      y: 0
+ *      width: 200
+ *      height: 200
+ *      // Provide the handle to the render window
+ *      renderWindow: vtkwindow
+ *    }
+ *  }
+ * @endcode
+ *
+ * The VTK pipeline can be then set up for each \b VTKRenderItem in the C++ code.
+ *
+ * ## QtQuick scenegraph and threaded render loop
+ *
+ * QtQuick/QML scenegraph rendering is done via private API inside the [QQuickWindow] class. For
+ * details on QtQuick's render loop, see [QtQuick Scenegraph Rendering](
+ * https://doc.qt.io/qt-6/qtquick-visualcanvas-scenegraph.html#scene-graph-and-rendering).
+ * Qt automatically decides between a threaded and basic render loop for most applications.
+ * QQuickVTKRenderWindow and QQuickVTKRenderItem support both these variants of the QtQuick render
+ * loop.
+ *
+ * When the scenegraph render loop is threaded, i.e. there is a dedicated rendering thread, vtk
+ * sticks to doing all rendering on this render thread. This means that all the vtk classes,
+ * pipelines etc. can be set up on the main thread but vtkRenderWindow::Render should only be
+ * invoked on the render thread. Care must be taken not to call Render on the main thread because
+ * the OpenGL context would not be valid on the main thread.
+ *
+ * [QQuickItem]: https://doc.qt.io/qt-5/qquickitem.html
+ * [QQuickWindow]: https://doc.qt.io/qt-5/qquickwindow.html
+ */
+
+#ifndef QQuickVTKRenderWindow_h
+#define QQuickVTKRenderWindow_h
+
+// vtk includes
+#include "vtkSmartPointer.h" // For vtkSmartPointer
+
+// Qt includes
+#include <QOpenGLFunctions> // For QOpenGLFunctions
+#include <QPointer>         // For QPointer
+#include <QQuickItem>
+
+#include "vtkGUISupportQtQuickModule.h" // for export macro
+
+// Forward declarations
+class QEvent;
+class QQuickVTKInteractorAdapter;
+class QQuickWindow;
+class QWheelEvent;
+class vtkGenericOpenGLRenderWindow;
+class vtkImageData;
+class vtkRenderWindow;
+class vtkWindowToImageFilter;
+
+class VTKGUISUPPORTQTQUICK_EXPORT QQuickVTKRenderWindow
+  : public QQuickItem
+  , protected QOpenGLFunctions
+{
+  Q_OBJECT
+  typedef QQuickItem Superclass;
+
+public:
+  /**
+   * Constructor
+   * Creates a QQuickVTKRenderWindow with:
+   *  - a vtkGenericOpenGLRenderWindow to manage the OpenGL context
+   *  - an interactor adapter to forward Qt events to vtk's interactor
+   */
+  QQuickVTKRenderWindow(QQuickItem* parent = nullptr);
+
+  /**
+   * Destructor
+   */
+  ~QQuickVTKRenderWindow();
+
+  ///@{
+  /**
+   * Set/Get the vtkRenderWindow for the view.
+   * Note that this render window should be of type vtkGenericOpenGLRenderWindow. This is necessary
+   * since that would allow vtk's opengl draw calls to work seamlessly inside the QtQuick created
+   * scenegraph and OpenGL context.
+   *
+   * By default, a vtkGenericOpenGLRenderWindow is created and set on this item at construction
+   * time.
+   */
+  void setRenderWindow(vtkRenderWindow* renWin);
+  void setRenderWindow(vtkGenericOpenGLRenderWindow* renWin);
+  vtkRenderWindow* renderWindow() const;
+  ///@}
+
+  /**
+   * Map a Qt item rect to viewport coordinates
+   */
+  virtual void mapToViewport(const QRectF& rect, double viewport[4]);
+
+  /**
+   * Get access to the interactor adapter
+   */
+  QPointer<QQuickVTKInteractorAdapter> interactorAdapter() const;
+
+  ///@{
+  /**
+   * Capture a screenshot of the window
+   *
+   * \param Viewport area to capture.
+   * \returns Image data containing the window capture.
+   * \note This triggers a scenegraph update to capture the render window view.
+   */
+  virtual vtkSmartPointer<vtkImageData> captureScreenshot();
+  virtual vtkSmartPointer<vtkImageData> captureScreenshot(double* viewport);
+  ///@}
+
+  /**
+   * Get whether the render window is initialized
+   * Used internally to determine if the OpenGL context, QQuickWindow, children items and viewports
+   * have been initialized.
+   */
+  virtual bool isInitialized() const;
+
+public Q_SLOTS:
+  /**
+   * This is the function called on the QtQuick render thread before the scenegraph state
+   * is synchronized. This is where most of the pipeline updates, camera manipulations, etc. and
+   * other pre-render steps can be performed.
+   *
+   * \note At the time of this method execution, the GUI thread is blocked. Hence, it is safe to
+   * perform state synchronization between the GUI elements and the VTK classes here.
+   */
+  virtual void sync();
+
+  /**
+   * This is the function called on the QtQuick render thread right before the scenegraph is
+   * rendered. This is the stage where all the vtk rendering is performed. Applications would rarely
+   * need to override this method.
+   *
+   * \note This method is called at the beforeRendering stage of the QtQuick scenegraph. All the
+   * QtQuick element rendering is stacked visually above the vtk rendering.
+   */
+  virtual void paint();
+
+  /**
+   * This is the function called on the QtQuick render thread when the scenegraph is invalidated.
+   * This is where all graphics resources allocated by vtk are released.
+   */
+  virtual void cleanup();
+
+  /**
+   * Convenience method that schedules a scenegraph update and waits for the update.
+   * @sa render()
+   */
+  virtual void renderNow();
+
+  /**
+   * Schedule a scenegraph update
+   *
+   * \note Since this schedules a scenegraph update, it does not guarantee that the scene will be
+   * updated after this call.
+   * \sa renderNow()
+   */
+  virtual void render();
+
+protected Q_SLOTS:
+  virtual void handleWindowChanged(QQuickWindow* w);
+
+protected:
+  QPointer<QQuickVTKInteractorAdapter> m_interactorAdapter;
+  vtkSmartPointer<vtkGenericOpenGLRenderWindow> m_renderWindow;
+  bool m_initialized = false;
+
+  // Screenshot stuff
+  bool m_screenshotScheduled = false;
+  vtkNew<vtkWindowToImageFilter> m_screenshotFilter;
+
+  // Event handlers
+  void geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry) override;
+
+private:
+  QQuickVTKRenderWindow(const QQuickVTKRenderWindow&) = delete;
+  void operator=(const QQuickVTKRenderWindow) = delete;
+};
+
+#endif // QQuickVTKRenderWindow_h
diff --git a/GUISupport/QtQuick/Testing/CMakeLists.txt b/GUISupport/QtQuick/Testing/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..49a7f4d6968a22f3e7ffd5a85674c4350a6c5598
--- /dev/null
+++ b/GUISupport/QtQuick/Testing/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(Cxx)
diff --git a/GUISupport/QtQuick/Testing/Cxx/CMakeLists.txt b/GUISupport/QtQuick/Testing/Cxx/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..24430fb9e652e819ec9b48126c9c3371d4d6080e
--- /dev/null
+++ b/GUISupport/QtQuick/Testing/Cxx/CMakeLists.txt
@@ -0,0 +1,30 @@
+find_package ("Qt${vtk_qt_major_version}"
+  COMPONENTS Quick Qml
+  REQUIRED
+  )
+
+set (CMAKE_AUTOMOC ON)
+set (CMAKE_AUTOUIC ON)
+set (CMAKE_AUTORCC ON)
+
+vtk_add_test_cxx (vtkGUISupportQtQuickCxxTests tests
+  TestQQuickVTKRenderItem.cxx
+  TestQQuickVTKRenderItemWidget.cxx
+  TestQQuickVTKRenderWindow.cxx
+  )
+
+vtk_test_cxx_executable(vtkGUISupportQtQuickCxxTests tests
+  TestQQuickVTK.qrc
+  )
+
+target_link_libraries(vtkGUISupportQtQuickCxxTests
+  PRIVATE
+    "Qt${vtk_qt_major_version}::Quick"
+    "Qt${vtk_qt_major_version}::Qml"
+    )
+
+set_tests_properties(
+  VTK::GUISupportQtQuickCxx-TestQQuickVTKRenderItem
+  VTK::GUISupportQtQuickCxx-TestQQuickVTKRenderItemWidget
+  VTK::GUISupportQtQuickCxx-TestQQuickVTKRenderWindow
+  PROPERTIES ENVIRONMENT "QML2_IMPORT_PATH=${CMAKE_BINARY_DIR}/$<CONFIG>")
diff --git a/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTK.qrc b/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTK.qrc
new file mode 100644
index 0000000000000000000000000000000000000000..f881f539f277f92d676f9421e739cf59e8cc36fc
--- /dev/null
+++ b/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTK.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+  <qresource prefix="/">
+    <file>TestQQuickVTKRenderItem.qml</file>
+    <file>TestQQuickVTKRenderItemWidget.qml</file>
+    <file>TestQQuickVTKRenderWindow.qml</file>
+  </qresource>
+</RCC>
diff --git a/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderItem.cxx b/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderItem.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..260f4ceb37e5de1af1a1a14b10c9e388fd90c03a
--- /dev/null
+++ b/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderItem.cxx
@@ -0,0 +1,107 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    TestQQuickVTKRenderItem.cxx
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+
+// Description
+// Tests QQuickVTKRenderItem
+
+#include "QQuickVTKRenderItem.h"
+#include "QQuickVTKRenderWindow.h"
+#include "vtkActor.h"
+#include "vtkConeSource.h"
+#include "vtkGenericOpenGLRenderWindow.h"
+#include "vtkNew.h"
+#include "vtkPNGWriter.h"
+#include "vtkPolyDataMapper.h"
+#include "vtkRenderer.h"
+#include "vtkTestUtilities.h"
+#include "vtkTesting.h"
+#include "vtkWindowToImageFilter.h"
+
+#include <QApplication>
+#include <QDebug>
+#include <QQmlApplicationEngine>
+#include <QQuickWindow>
+#include <QTimer>
+#include <QUrl>
+
+int TestQQuickVTKRenderItem(int argc, char* argv[])
+{
+  cout << "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)" << endl;
+
+  QApplication app(argc, argv);
+
+  QQmlApplicationEngine engine;
+  qDebug() << "QML2_IMPORT_PATH:" << engine.importPathList();
+  engine.load(QUrl("qrc:///TestQQuickVTKRenderItem.qml"));
+
+  QObject* topLevel = engine.rootObjects().value(0);
+  QQuickWindow* window = qobject_cast<QQuickWindow*>(topLevel);
+
+  window->show();
+
+  // Fetch the QQuick window using the standard object name set up in the constructor
+  QQuickVTKRenderItem* qquickvtkItem = topLevel->findChild<QQuickVTKRenderItem*>("ConeView");
+
+  // Create a cone pipeline and add it to the view
+  vtkNew<vtkActor> actor;
+  vtkNew<vtkPolyDataMapper> mapper;
+  vtkNew<vtkConeSource> cone;
+  mapper->SetInputConnection(cone->GetOutputPort());
+  actor->SetMapper(mapper);
+  qquickvtkItem->renderer()->AddActor(actor);
+  qquickvtkItem->renderer()->ResetCamera();
+  qquickvtkItem->renderer()->SetBackground(0.5, 0.5, 0.7);
+  qquickvtkItem->renderer()->SetBackground2(0.7, 0.7, 0.7);
+  qquickvtkItem->renderer()->SetGradientBackground(true);
+  qquickvtkItem->update();
+
+  vtkNew<vtkTesting> vtktesting;
+  vtktesting->AddArguments(argc, argv);
+  if (vtktesting->IsInteractiveModeSpecified())
+  {
+    return app.exec();
+  }
+
+  // Wait a little for the application and window to be set up properly
+  QEventLoop loop;
+  QTimer::singleShot(100, &loop, SLOT(quit()));
+  loop.exec();
+
+  // Capture a screenshot of the item
+  vtkSmartPointer<vtkImageData> im = qquickvtkItem->captureScreenshot();
+
+  std::string validName = std::string(vtktesting->GetValidImageFileName());
+  std::string::size_type slashPos = validName.rfind('/');
+  if (slashPos != std::string::npos)
+  {
+    validName = validName.substr(slashPos + 1);
+  }
+  std::string tmpDir = vtktesting->GetTempDirectory();
+  std::string vImage = tmpDir + "/" + validName;
+  vtkNew<vtkPNGWriter> w;
+  w->SetInputData(im);
+  w->SetFileName(vImage.c_str());
+  w->Write();
+
+  int retVal = vtktesting->RegressionTest(vImage, 10);
+
+  switch (retVal)
+  {
+    case vtkTesting::FAILED:
+    case vtkTesting::NOT_RUN:
+      return EXIT_FAILURE;
+  }
+  return EXIT_SUCCESS;
+}
diff --git a/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderItem.qml b/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderItem.qml
new file mode 100644
index 0000000000000000000000000000000000000000..48d1cbc4fb57fc94701752f85b955cc1d780fb8e
--- /dev/null
+++ b/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderItem.qml
@@ -0,0 +1,74 @@
+// import related modules
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Window 2.15
+
+// import the VTK module
+import VTK 9.0
+
+// window containing the application
+ApplicationWindow {
+  // title of the application
+  title: qsTr("VTK QtQuick App")
+  width: 400
+  height: 400
+  color: palette.window
+
+  SystemPalette {
+    id: palette
+    colorGroup: SystemPalette.Active
+  }
+
+  // menubar with two menus
+  menuBar: MenuBar {
+    Menu {
+      title: qsTr("File")
+      MenuItem {
+        text: qsTr("&Quit")
+        onTriggered: Qt.quit()
+      }
+    }
+    Menu {
+      title: qsTr("Edit")
+    }
+  }
+
+  // Content area
+
+  // a rectangle in the middle of the content area
+  Rectangle {
+    width: 100
+    height: 100
+    color: "blue"
+    border.color: "red"
+    border.width: 5
+    radius: 10
+  }
+  Text {
+      id: label
+      color: "white"
+      wrapMode: Text.WordWrap
+      text: "Custom QML\nrectangle &\ntext"
+      anchors.right: parent.right
+      anchors.left: parent.left
+      anchors.top: parent.top
+      anchors.margins: 10
+      width: 100
+  }
+
+  VTKRenderWindow {
+    id: vtkwindow
+    width: 400
+    height: 400
+  }
+
+  VTKRenderItem {
+    objectName: "ConeView"
+    x: 200
+    y: 200
+    width: 200
+    height: 200
+    renderWindow: vtkwindow
+    focus: true
+  }
+}
diff --git a/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderItemWidget.cxx b/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderItemWidget.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..49f652d29f48f119808160512ca6cf957b0f55cb
--- /dev/null
+++ b/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderItemWidget.cxx
@@ -0,0 +1,216 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    TestQQuickVTKRenderItemWidget.cxx
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+
+// Description
+// Tests QQuickVTKRenderItem
+
+#include "QQuickVTKInteractiveWidget.h"
+#include "QQuickVTKRenderItem.h"
+#include "QQuickVTKRenderWindow.h"
+#include "vtkActor.h"
+#include "vtkAppendPolyData.h"
+#include "vtkCamera.h"
+#include "vtkClipPolyData.h"
+#include "vtkCommand.h"
+#include "vtkConeSource.h"
+#include "vtkGenericOpenGLRenderWindow.h"
+#include "vtkGlyph3D.h"
+#include "vtkImplicitPlaneRepresentation.h"
+#include "vtkImplicitPlaneWidget2.h"
+#include "vtkInteractorEventRecorder.h"
+#include "vtkNew.h"
+#include "vtkPNGWriter.h"
+#include "vtkPlane.h"
+#include "vtkPolyData.h"
+#include "vtkPolyDataMapper.h"
+#include "vtkProperty.h"
+#include "vtkRenderWindowInteractor.h"
+#include "vtkRenderer.h"
+#include "vtkSphereSource.h"
+#include "vtkTestUtilities.h"
+#include "vtkTesting.h"
+#include "vtkWindowToImageFilter.h"
+
+#include <QApplication>
+#include <QDebug>
+#include <QQmlApplicationEngine>
+#include <QQuickWindow>
+#include <QTimer>
+#include <QUrl>
+
+class TestQQuickVTKRenderItemWidgetCallback : public vtkCommand
+{
+public:
+  static TestQQuickVTKRenderItemWidgetCallback* New()
+  {
+    return new TestQQuickVTKRenderItemWidgetCallback;
+  }
+  void Execute(vtkObject* caller, unsigned long, void*) override
+  {
+    vtkImplicitPlaneWidget2* planeWidget = reinterpret_cast<vtkImplicitPlaneWidget2*>(caller);
+    vtkImplicitPlaneRepresentation* rep =
+      reinterpret_cast<vtkImplicitPlaneRepresentation*>(planeWidget->GetRepresentation());
+    rep->GetPlane(this->Plane);
+    this->Actor->VisibilityOn();
+  }
+  TestQQuickVTKRenderItemWidgetCallback()
+    : Plane(nullptr)
+    , Actor(nullptr)
+  {
+  }
+  vtkPlane* Plane;
+  vtkActor* Actor;
+};
+
+int TestQQuickVTKRenderItemWidget(int argc, char* argv[])
+{
+  cout << "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)" << endl;
+
+  QApplication app(argc, argv);
+
+  QQmlApplicationEngine engine;
+  qDebug() << "QML2_IMPORT_PATH:" << engine.importPathList();
+  engine.load(QUrl("qrc:///TestQQuickVTKRenderItemWidget.qml"));
+
+  QObject* topLevel = engine.rootObjects().value(0);
+  QQuickWindow* window = qobject_cast<QQuickWindow*>(topLevel);
+
+  window->show();
+
+  // Fetch the QQuick window using the standard object name set up in the constructor
+  QQuickVTKRenderWindow* qquickvtkWindow =
+    topLevel->findChild<QQuickVTKRenderWindow*>("QQuickVTKRenderWindow");
+
+  // Fetch the QQuick item using the object name set up in the qml file
+  QQuickVTKRenderItem* coneItem = topLevel->findChild<QQuickVTKRenderItem*>("ConeView");
+  // Create a cone pipeline and add it to the view
+  vtkNew<vtkActor> actor;
+  vtkNew<vtkPolyDataMapper> mapper;
+  vtkNew<vtkConeSource> cone;
+  mapper->SetInputConnection(cone->GetOutputPort());
+  actor->SetMapper(mapper);
+  coneItem->renderer()->AddActor(actor);
+  coneItem->renderer()->SetBackground(0.5, 0.5, 0.7);
+  coneItem->renderer()->SetBackground2(0.7, 0.7, 0.7);
+  coneItem->renderer()->SetGradientBackground(true);
+  coneItem->update();
+
+  // Fetch the QQuick item using the object name set up in the qml file
+  QQuickVTKRenderItem* widgetItem = topLevel->findChild<QQuickVTKRenderItem*>("WidgetView");
+  // Create a mace out of filters.
+  //
+  vtkNew<vtkSphereSource> sphere;
+  vtkNew<vtkGlyph3D> glyph;
+  glyph->SetInputConnection(sphere->GetOutputPort());
+  glyph->SetSourceConnection(cone->GetOutputPort());
+  glyph->SetVectorModeToUseNormal();
+  glyph->SetScaleModeToScaleByVector();
+  glyph->SetScaleFactor(0.25);
+
+  // The sphere and spikes are appended into a single polydata.
+  // This just makes things simpler to manage.
+  vtkNew<vtkAppendPolyData> apd;
+  apd->AddInputConnection(glyph->GetOutputPort());
+  apd->AddInputConnection(sphere->GetOutputPort());
+
+  vtkNew<vtkPolyDataMapper> maceMapper;
+  maceMapper->SetInputConnection(apd->GetOutputPort());
+
+  vtkNew<vtkActor> maceActor;
+  maceActor->SetMapper(maceMapper);
+  maceActor->VisibilityOn();
+
+  // This portion of the code clips the mace with the vtkPlanes
+  // implicit function. The clipped region is colored green.
+  vtkNew<vtkPlane> plane;
+  vtkNew<vtkClipPolyData> clipper;
+  clipper->SetInputConnection(apd->GetOutputPort());
+  clipper->SetClipFunction(plane);
+  clipper->InsideOutOn();
+
+  vtkNew<vtkPolyDataMapper> selectMapper;
+  selectMapper->SetInputConnection(clipper->GetOutputPort());
+
+  vtkNew<vtkActor> selectActor;
+  selectActor->SetMapper(selectMapper);
+  selectActor->GetProperty()->SetColor(0, 1, 0);
+  selectActor->VisibilityOff();
+  selectActor->SetScale(1.01, 1.01, 1.01);
+
+  // The SetInteractor method is how 3D widgets are associated with the render
+  // window interactor. Internally, SetInteractor sets up a bunch of callbacks
+  // using the Command/Observer mechanism (AddObserver()).
+  vtkNew<TestQQuickVTKRenderItemWidgetCallback> myCallback;
+  myCallback->Plane = plane;
+  myCallback->Actor = selectActor;
+
+  vtkNew<vtkImplicitPlaneRepresentation> rep;
+  vtkNew<vtkImplicitPlaneWidget2> planeWidget;
+  planeWidget->SetRepresentation(rep);
+  planeWidget->AddObserver(vtkCommand::InteractionEvent, myCallback);
+
+  QQuickVTKInteractiveWidget* qquickVTKWidget = new QQuickVTKInteractiveWidget(window);
+  qquickVTKWidget->setWidget(planeWidget);
+  qquickVTKWidget->setEnabled(true);
+
+  widgetItem->renderer()->AddActor(maceActor);
+  widgetItem->renderer()->AddActor(selectActor);
+  widgetItem->addWidget(qquickVTKWidget);
+  widgetItem->update();
+
+  // Wait a little for the application and window to be set up properly
+  QEventLoop loop;
+  QTimer::singleShot(100, &loop, SLOT(quit()));
+  loop.exec();
+
+  // Once the application is up, adjust the camera, widget reps, etc.
+  widgetItem->renderer()->ResetCamera();
+  rep->SetPlaceFactor(1.25);
+  rep->PlaceWidget(glyph->GetOutput()->GetBounds());
+  widgetItem->renderer()->GetActiveCamera()->Azimuth(20);
+
+  vtkNew<vtkTesting> vtktesting;
+  vtktesting->AddArguments(argc, argv);
+  if (vtktesting->IsInteractiveModeSpecified())
+  {
+    return app.exec();
+  }
+
+  // Capture a screenshot of the item
+  vtkSmartPointer<vtkImageData> im = qquickvtkWindow->captureScreenshot();
+
+  std::string validName = std::string(vtktesting->GetValidImageFileName());
+  std::string::size_type slashPos = validName.rfind('/');
+  if (slashPos != std::string::npos)
+  {
+    validName = validName.substr(slashPos + 1);
+  }
+  std::string tmpDir = vtktesting->GetTempDirectory();
+  std::string vImage = tmpDir + "/" + validName;
+  vtkNew<vtkPNGWriter> w;
+  w->SetInputData(im);
+  w->SetFileName(vImage.c_str());
+  w->Write();
+
+  int retVal = vtktesting->RegressionTest(vImage, 10);
+
+  switch (retVal)
+  {
+    case vtkTesting::FAILED:
+    case vtkTesting::NOT_RUN:
+      return EXIT_FAILURE;
+  }
+  return EXIT_SUCCESS;
+}
diff --git a/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderItemWidget.qml b/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderItemWidget.qml
new file mode 100644
index 0000000000000000000000000000000000000000..0a24e709755fad18101ee8ebc800599bc9b6b1eb
--- /dev/null
+++ b/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderItemWidget.qml
@@ -0,0 +1,89 @@
+// import related modules
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+import QtQuick.Window 2.15
+
+// import the VTK module
+import VTK 9.0
+
+// window containing the application
+ApplicationWindow {
+  // title of the application
+  title: qsTr("VTK QtQuick App")
+  width: 800
+  height: 800
+  color: palette.window
+
+  SystemPalette {
+    id: palette
+    colorGroup: SystemPalette.Active
+  }
+
+  // menubar with two menus
+  menuBar: MenuBar {
+    Menu {
+      title: qsTr("File")
+      MenuItem {
+        text: qsTr("&Quit")
+        onTriggered: Qt.quit()
+      }
+    }
+    Menu {
+      title: qsTr("Edit")
+    }
+  }
+
+  // Content area
+
+  // a rectangle in the middle of the content area
+  Rectangle {
+    width: 100
+    height: 100
+    color: "blue"
+    border.color: "red"
+    border.width: 5
+    radius: 10
+  }
+  Text {
+    id: label
+    color: "white"
+    wrapMode: Text.WordWrap
+    text: "Custom QML\nrectangle &\ntext"
+    anchors.right: parent.right
+    anchors.left: parent.left
+    anchors.top: parent.top
+    anchors.margins: 10
+    width: 100
+  }
+
+  VTKRenderWindow {
+    id: vtkwindow
+    anchors.fill: parent
+  }
+
+  RowLayout {
+    anchors.fill: parent
+
+    VTKRenderItem {
+      objectName: "ConeView"
+      Layout.column: 0
+      Layout.fillWidth: true
+      Layout.fillHeight: true
+      Layout.minimumWidth: 100
+      Layout.preferredWidth: 200
+      renderWindow: vtkwindow
+      focus: true
+    }
+    VTKRenderItem {
+      objectName: "WidgetView"
+      Layout.column: 1
+      Layout.fillWidth: true
+      Layout.fillHeight: true
+      Layout.minimumWidth: 100
+      Layout.preferredWidth: 400
+      renderWindow: vtkwindow
+      focus: true
+    }
+  }
+}
diff --git a/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderWindow.cxx b/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderWindow.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..a35467d2d12ed5c61f057bfa5838b2c596207a9e
--- /dev/null
+++ b/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderWindow.cxx
@@ -0,0 +1,174 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    TestQQuickVTKRenderWindow.cxx
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+
+// Description
+// Tests QQuickVTKRenderWindow/QQuickVTKRenderItem
+
+#include "QQuickVTKRenderItem.h"
+#include "QQuickVTKRenderWindow.h"
+#include "vtkActor.h"
+#include "vtkColorTransferFunction.h"
+#include "vtkConeSource.h"
+#include "vtkGenericOpenGLRenderWindow.h"
+#include "vtkGlyph3DMapper.h"
+#include "vtkNew.h"
+#include "vtkPNGWriter.h"
+#include "vtkPiecewiseFunction.h"
+#include "vtkPolyDataMapper.h"
+#include "vtkProperty.h"
+#include "vtkRenderer.h"
+#include "vtkSmartVolumeMapper.h"
+#include "vtkSphereSource.h"
+#include "vtkTestUtilities.h"
+#include "vtkTesting.h"
+#include "vtkVolume.h"
+#include "vtkVolumeProperty.h"
+#include "vtkWindowToImageFilter.h"
+#include "vtkXMLImageDataReader.h"
+
+#include <QApplication>
+#include <QDebug>
+#include <QQmlApplicationEngine>
+#include <QQuickWindow>
+#include <QTimer>
+#include <QUrl>
+
+int TestQQuickVTKRenderWindow(int argc, char* argv[])
+{
+  cout << "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)" << endl;
+
+  QApplication app(argc, argv);
+
+  QQmlApplicationEngine engine;
+  qDebug() << "QML2_IMPORT_PATH:" << engine.importPathList();
+  engine.load(QUrl("qrc:///TestQQuickVTKRenderWindow.qml"));
+
+  QObject* topLevel = engine.rootObjects().value(0);
+  QQuickWindow* window = qobject_cast<QQuickWindow*>(topLevel);
+
+  window->show();
+
+  // Fetch the QQuick window using the standard object name set up in the constructor
+  QQuickVTKRenderItem* geomItem = topLevel->findChild<QQuickVTKRenderItem*>("GeomView");
+
+  // Create a cone pipeline and add it to the view
+  vtkNew<vtkActor> actor;
+  vtkNew<vtkPolyDataMapper> mapper;
+  vtkNew<vtkConeSource> cone;
+  mapper->SetInputConnection(cone->GetOutputPort());
+  actor->SetMapper(mapper);
+  geomItem->renderer()->AddActor(actor);
+  geomItem->renderer()->ResetCamera();
+  // geomItem->renderer()->SetBackground(0.5, 0.5, 0.7);
+  geomItem->renderer()->SetBackground2(0.7, 0.7, 0.7);
+  // geomItem->renderer()->SetGradientBackground(true);
+  geomItem->update();
+
+  // Now the volume view
+  QQuickVTKRenderItem* volumeItem = topLevel->findChild<QQuickVTKRenderItem*>("VolumeView");
+
+  // Create a volume pipeline and add it to the view
+  vtkNew<vtkSmartVolumeMapper> volumeMapper;
+  vtkNew<vtkXMLImageDataReader> reader;
+  const char* volumeFile = vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/vase_1comp.vti");
+  reader->SetFileName(volumeFile);
+  volumeMapper->SetInputConnection(reader->GetOutputPort());
+  delete[] volumeFile;
+  double scalarRange[2];
+  volumeMapper->GetInput()->GetScalarRange(scalarRange);
+  volumeMapper->SetAutoAdjustSampleDistances(1);
+  volumeMapper->SetBlendModeToComposite();
+  vtkNew<vtkPiecewiseFunction> scalarOpacity;
+  scalarOpacity->AddPoint(scalarRange[0], 0.0);
+  scalarOpacity->AddPoint(scalarRange[1], 0.09);
+  vtkNew<vtkVolumeProperty> volumeProperty;
+  volumeProperty->ShadeOff();
+  volumeProperty->SetInterpolationType(VTK_LINEAR_INTERPOLATION);
+  volumeProperty->SetScalarOpacity(scalarOpacity);
+  vtkSmartPointer<vtkColorTransferFunction> colorTransferFunction =
+    volumeProperty->GetRGBTransferFunction(0);
+  colorTransferFunction->RemoveAllPoints();
+  colorTransferFunction->AddRGBPoint(scalarRange[0], 0.6, 0.4, 0.1);
+  // colorTransferFunction->AddRGBPoint(scalarRange[1], 0.2, 0.1, 0.3);
+  vtkSmartPointer<vtkVolume> volume = vtkSmartPointer<vtkVolume>::New();
+  volume->SetMapper(volumeMapper);
+  volume->SetProperty(volumeProperty);
+  volumeItem->renderer()->AddVolume(volume);
+  volumeItem->renderer()->ResetCamera();
+  // volumeItem->renderer()->SetBackground(0.5, 0.5, 0.7);
+  volumeItem->renderer()->SetBackground(0, 0, 1);
+  // volumeItem->renderer()->SetBackground2(0.7, 0.7, 0.7);
+  volumeItem->update();
+
+  // Now the glyph view
+  QQuickVTKRenderItem* glyphItem = topLevel->findChild<QQuickVTKRenderItem*>("GlyphView");
+
+  // Create the glyph pipeline
+  vtkNew<vtkSphereSource> sphere;
+  vtkNew<vtkGlyph3DMapper> glyphMapper;
+  vtkNew<vtkConeSource> squad;
+  glyphMapper->SetInputConnection(sphere->GetOutputPort());
+  glyphMapper->SetSourceConnection(squad->GetOutputPort());
+  glyphMapper->SetOrientationArray("Normals");
+  vtkNew<vtkActor> glyphActor;
+  glyphActor->SetMapper(glyphMapper);
+  glyphActor->GetProperty()->SetDiffuseColor(0.5, 1.0, 0.8);
+  glyphItem->renderer()->AddActor(glyphActor);
+  glyphItem->renderer()->SetBackground(0.5, 0.5, 0.7);
+  glyphItem->renderer()->ResetCamera();
+  glyphItem->update();
+
+  // Now the testing
+  vtkNew<vtkTesting> vtktesting;
+  vtktesting->AddArguments(argc, argv);
+  if (vtktesting->IsInteractiveModeSpecified())
+  {
+    return app.exec();
+  }
+
+  // Wait a little for the application and window to be set up properly
+  QEventLoop loop;
+  QTimer::singleShot(100, &loop, SLOT(quit()));
+  loop.exec();
+
+  // Capture a screenshot of the window
+  // Fetch the QQuick window using the standard object name set up in the constructor
+  QQuickVTKRenderWindow* qquickvtkWindow =
+    topLevel->findChild<QQuickVTKRenderWindow*>("QQuickVTKRenderWindow");
+  vtkSmartPointer<vtkImageData> im = qquickvtkWindow->captureScreenshot();
+
+  std::string validName = std::string(vtktesting->GetValidImageFileName());
+  std::string::size_type slashPos = validName.rfind('/');
+  if (slashPos != std::string::npos)
+  {
+    validName = validName.substr(slashPos + 1);
+  }
+  std::string tmpDir = vtktesting->GetTempDirectory();
+  std::string vImage = tmpDir + "/" + validName;
+  vtkNew<vtkPNGWriter> w;
+  w->SetInputData(im);
+  w->SetFileName(vImage.c_str());
+  w->Write();
+
+  int retVal = vtktesting->RegressionTest(vImage, 10);
+
+  switch (retVal)
+  {
+    case vtkTesting::FAILED:
+    case vtkTesting::NOT_RUN:
+      return EXIT_FAILURE;
+  }
+  return EXIT_SUCCESS;
+}
diff --git a/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderWindow.qml b/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderWindow.qml
new file mode 100644
index 0000000000000000000000000000000000000000..0f3ae83ab8f9b7678660852dba0ee6a02d804f2b
--- /dev/null
+++ b/GUISupport/QtQuick/Testing/Cxx/TestQQuickVTKRenderWindow.qml
@@ -0,0 +1,79 @@
+// import related modules
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+import QtQuick.Window 2.15
+
+// import the VTK module
+import VTK 9.0
+
+// window containing the application
+ApplicationWindow {
+  // title of the application
+  title: qsTr("VTK QtQuick App")
+  width: 800
+  height: 600
+  color: palette.window
+
+  SystemPalette {
+    id: palette
+    colorGroup: SystemPalette.Active
+  }
+
+  // menubar with two menus
+  menuBar: MenuBar {
+    Menu {
+      title: qsTr("File")
+      MenuItem {
+        text: qsTr("&Quit")
+        onTriggered: Qt.quit()
+      }
+    }
+    Menu {
+      title: qsTr("Edit")
+    }
+  }
+
+  // Content area
+  // Create a VTK render window to represent the opengl context for all vtk items in this app
+  VTKRenderWindow {
+    id: vtkwindow
+    anchors.fill: parent
+  }
+
+  SplitView {
+    anchors.fill: parent
+    orientation: Qt.Horizontal
+
+    VTKRenderItem {
+      objectName: "VolumeView"
+      SplitView.fillHeight: true
+      SplitView.fillWidth: true
+      SplitView.minimumHeight: 100
+      SplitView.minimumWidth: 100
+      SplitView.preferredHeight: 200
+      SplitView.preferredWidth: 200
+      renderWindow: vtkwindow
+    }
+
+    ColumnLayout {
+      SplitView.fillHeight: true
+      SplitView.fillWidth: true
+      SplitView.minimumWidth: 200
+      SplitView.preferredWidth: 200
+      VTKRenderItem {
+        objectName: "GlyphView"
+        renderWindow: vtkwindow
+        focus: true
+        Layout.fillHeight: true
+        Layout.fillWidth: true
+      }
+      VTKRenderItem {
+        objectName: "GeomView"
+        renderWindow: vtkwindow
+        Layout.fillHeight: true
+        Layout.fillWidth: true
+      }
+    }
+  }
+}
diff --git a/GUISupport/QtQuick/Testing/Data/Baseline/TestQQuickVTKRenderItem.png.sha512 b/GUISupport/QtQuick/Testing/Data/Baseline/TestQQuickVTKRenderItem.png.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..9883fcc2e9aefa4c48113d1732dcdb4754147548
--- /dev/null
+++ b/GUISupport/QtQuick/Testing/Data/Baseline/TestQQuickVTKRenderItem.png.sha512
@@ -0,0 +1 @@
+9c2b68d8a43af9f3d5b0fd6ac9f32c60491fb94d9dab595d2d6e670b6627a38a2e9614e4a484d75bd33d623fc7835d023aeafd236a54964069f5c445e8161855
diff --git a/GUISupport/QtQuick/Testing/Data/Baseline/TestQQuickVTKRenderItemWidget.png.sha512 b/GUISupport/QtQuick/Testing/Data/Baseline/TestQQuickVTKRenderItemWidget.png.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..a8f108dbbe544c16a37cc53a9dee1c655716b9ba
--- /dev/null
+++ b/GUISupport/QtQuick/Testing/Data/Baseline/TestQQuickVTKRenderItemWidget.png.sha512
@@ -0,0 +1 @@
+cc5a009273ed6a1fa6f3485a7d6b80bcda445eff1883cdb7f7dd72696308c81f88a778a8cf0494030af5e231f9ed13d1b6e852a4ba6365d90abdab65075250a0
diff --git a/GUISupport/QtQuick/Testing/Data/Baseline/TestQQuickVTKRenderWindow.png.sha512 b/GUISupport/QtQuick/Testing/Data/Baseline/TestQQuickVTKRenderWindow.png.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..91e412f287041064b1e6c85f2e261a0500f48d58
--- /dev/null
+++ b/GUISupport/QtQuick/Testing/Data/Baseline/TestQQuickVTKRenderWindow.png.sha512
@@ -0,0 +1 @@
+232d2ec5e01d5704c630209e575227ba44b1db09c84643a75b6ab975101975a4794252d3b4a8a1d50f7d1a5872090cc88dde3a857c5284d9901bf71718133116
diff --git a/GUISupport/QtQuick/VTK.qmltypes b/GUISupport/QtQuick/VTK.qmltypes
new file mode 100644
index 0000000000000000000000000000000000000000..80fca3bba0a63b32e31b4fced94608ffbe9fcd93
--- /dev/null
+++ b/GUISupport/QtQuick/VTK.qmltypes
@@ -0,0 +1,49 @@
+import QtQuick.tooling 1.2
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump VTK 9.0 /home/sankhesh/Projects/vtk/bld-release/Release/'
+
+Module {
+    dependencies: ["QtQuick 2.0"]
+    Component {
+        name: "QQuickVTKInteractiveWidget"
+        prototype: "QObject"
+        exports: ["VTKWidget 9.0"]
+        exportMetaObjectRevisions: [0]
+        Property { name: "enabled"; type: "bool" }
+        Signal {
+            name: "enabledChanged"
+            Parameter { name: "e"; type: "bool" }
+        }
+        Method {
+            name: "sync"
+            Parameter { name: "ren"; type: "vtkRenderer"; isPointer: true }
+        }
+    }
+    Component {
+        name: "QQuickVTKRenderItem"
+        defaultProperty: "data"
+        prototype: "QQuickItem"
+        exports: ["VTKRenderItem 9.0"]
+        exportMetaObjectRevisions: [0]
+        Property { name: "renderWindow"; type: "QQuickVTKRenderWindow"; isPointer: true }
+        Method { name: "sync" }
+        Method { name: "paint" }
+        Method { name: "cleanup" }
+    }
+    Component {
+        name: "QQuickVTKRenderWindow"
+        defaultProperty: "data"
+        prototype: "QQuickItem"
+        exports: ["VTKRenderWindow 9.0"]
+        exportMetaObjectRevisions: [0]
+        Method { name: "sync" }
+        Method { name: "paint" }
+        Method { name: "cleanup" }
+        Method { name: "renderNow" }
+        Method { name: "render" }
+    }
+}
diff --git a/GUISupport/QtQuick/qmldir.in b/GUISupport/QtQuick/qmldir.in
new file mode 100644
index 0000000000000000000000000000000000000000..dd5e9cec5800c9004f7a587ce7c9bed5543cf7b4
--- /dev/null
+++ b/GUISupport/QtQuick/qmldir.in
@@ -0,0 +1,4 @@
+module @_vtk_build_PACKAGE@
+plugin @VTK_MODULE_PLUGIN_NAME@ @VTK_MODULE_PLUGIN_DIR@
+classname QQmlVTKPlugin
+typeinfo @_vtk_build_PACKAGE@.qmltypes
diff --git a/GUISupport/QtQuick/vtk.module b/GUISupport/QtQuick/vtk.module
new file mode 100644
index 0000000000000000000000000000000000000000..f0078ba74a72fb51a5a91b74aac7ba009ff87840
--- /dev/null
+++ b/GUISupport/QtQuick/vtk.module
@@ -0,0 +1,25 @@
+NAME
+  VTK::GUISupportQtQuick
+LIBRARY_NAME
+  vtkGUISupportQtQuick
+GROUPS
+  Qt
+DEPENDS
+  VTK::CommonCore
+  VTK::GUISupportQt
+  VTK::InteractionWidgets
+  VTK::RenderingCore
+  VTK::RenderingOpenGL2
+PRIVATE_DEPENDS
+  VTK::CommonDataModel
+  VTK::FiltersExtraction
+  VTK::InteractionStyle
+  VTK::opengl
+TEST_DEPENDS
+  VTK::FiltersSources
+  VTK::IOImage
+  VTK::IOXML
+  VTK::RenderingVolumeOpenGL2
+  VTK::TestingCore
+  VTK::TestingRendering
+EXCLUDE_WRAP