diff --git a/assets/docs/blog/2025-10-06-html-flow/images/cover.png b/assets/docs/blog/2025-10-06-html-flow/images/cover.png
new file mode 100644
index 00000000..b53abc82
Binary files /dev/null and b/assets/docs/blog/2025-10-06-html-flow/images/cover.png differ
diff --git a/assets/docs/blog/2025-10-06-html-flow/index.md b/assets/docs/blog/2025-10-06-html-flow/index.md
new file mode 100644
index 00000000..ba32447f
--- /dev/null
+++ b/assets/docs/blog/2025-10-06-html-flow/index.md
@@ -0,0 +1,35 @@
+---
+title: HTML Flow Component
+date: 2025-10-06
+author: Mathieu Ledru
+cover: images/cover.png
+coverSeo: images/cover.png
+coverAuthor: Html
+coverOriginalUrl: https://www.w3schools.com/html
+tags: ["blog", "components", "html"]
+---
+
+Introducing HTML Flow: Safe HTML Rendering in Your Automation Flows! 🎨
+We're excited to announce the new HTML Flow component for Uniflow. This powerful addition allows you to safely render HTML content stored in variables directly within your automation flows.
+
+The HTML Flow component provides secure HTML rendering with built-in sanitization, making it perfect for displaying dynamic content, embedded media, or custom layouts in your automation interfaces.
+
+### Key Features
+
+- **Safe HTML Rendering**: The component automatically sanitizes HTML content, removing potentially dangerous elements like scripts, forms, and malicious attributes while preserving safe content like iframes with proper restrictions.
+- **Variable Integration**: Simply specify a variable name that contains your HTML content, and the component will automatically fetch and display it from the runner context.
+- **Real-time Preview**: See your HTML content rendered live as you build your flows, with immediate visual feedback.
+- **Iframe Support**: Safely embed external content through iframes with automatic URL validation and attribute filtering.
+
+### How It Works
+
+The HTML Flow component takes a single input - the name of a variable containing HTML content. It then:
+
+1. Fetches the HTML from the runner context
+2. Sanitizes the content using custom DOM filtering
+3. Renders the safe HTML directly in the preview pane
+4. Updates automatically when the variable content changes
+
+Perfect for creating rich, interactive automation interfaces that can display dynamic content, embedded media, or custom layouts while maintaining security and performance.
+
+Let's make your flows not just functional, but visually engaging! 🚀
diff --git a/assets/docs/changelog.yaml b/assets/docs/changelog.yaml
index 3cd5e52d..333e2b73 100644
--- a/assets/docs/changelog.yaml
+++ b/assets/docs/changelog.yaml
@@ -1,3 +1,7 @@
+- tag: "v1.1.18"
+ label: |-
+ Add HTML Flow Component
+ date: "2025-10-06"
- tag: "v1.1.17"
label: |-
Migrate to Symfony UX
diff --git a/assets/shop/components/flow-assets/index.jsx b/assets/shop/components/flow/assets-flow.jsx
similarity index 97%
rename from assets/shop/components/flow-assets/index.jsx
rename to assets/shop/components/flow/assets-flow.jsx
index 9d172190..95fbc098 100644
--- a/assets/shop/components/flow-assets/index.jsx
+++ b/assets/shop/components/flow/assets-flow.jsx
@@ -1,11 +1,10 @@
import React, { useImperativeHandle } from 'react'
-import FlowHeader from '../flow/header.jsx'
+import FlowHeader from './header.jsx'
import FormInput, { FormInputType } from '../form-input.jsx'
-import { flow } from '../flow/flow.jsx'
+import { flow } from './flow.jsx'
import LZString from 'lz-string'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faDownload, faTimes } from '@fortawesome/free-solid-svg-icons'
-import { ClientType } from '../../models/client-type';
const AssetsFlow = flow((props, ref) => {
const { onPop, onUpdate, onPlay, onStop, isPlaying, data, clients } = props
diff --git a/assets/shop/components/flow-canvas/index.jsx b/assets/shop/components/flow/canvas-flow.jsx
similarity index 95%
rename from assets/shop/components/flow-canvas/index.jsx
rename to assets/shop/components/flow/canvas-flow.jsx
index 2e9c1899..27de88ed 100644
--- a/assets/shop/components/flow-canvas/index.jsx
+++ b/assets/shop/components/flow/canvas-flow.jsx
@@ -1,9 +1,8 @@
import React, { useImperativeHandle } from 'react'
-import FlowHeader from '../flow/header.jsx'
+import FlowHeader from './header.jsx'
import FormInput, { FormInputType } from '../form-input.jsx'
-import { flow } from '../flow/flow.jsx'
+import { flow } from './flow.jsx'
import { useRef } from 'react'
-import { ClientType } from '../../models/client-type';
// Canvas flow data shape:
// {
diff --git a/assets/shop/components/flow-function/index.jsx b/assets/shop/components/flow/function-flow.jsx
similarity index 90%
rename from assets/shop/components/flow-function/index.jsx
rename to assets/shop/components/flow/function-flow.jsx
index e1c9164c..15ec09c8 100644
--- a/assets/shop/components/flow-function/index.jsx
+++ b/assets/shop/components/flow/function-flow.jsx
@@ -1,8 +1,7 @@
import React, { useImperativeHandle } from 'react'
-import FlowHeader from '../flow/header.jsx'
+import FlowHeader from './header.jsx'
import FormInput, { FormInputType } from '../form-input.jsx'
-import { flow } from '../flow/flow.jsx'
-import { ClientType } from '../../models/client-type';
+import { flow } from './flow.jsx'
/**
* @typedef {Object} FunctionFlowData
diff --git a/assets/shop/components/flow/html-flow.jsx b/assets/shop/components/flow/html-flow.jsx
new file mode 100644
index 00000000..95e34733
--- /dev/null
+++ b/assets/shop/components/flow/html-flow.jsx
@@ -0,0 +1,120 @@
+import React, { useImperativeHandle, useMemo } from 'react'
+import FlowHeader from './header.jsx'
+import FormInput, { FormInputType } from '../form-input.jsx'
+import { flow } from './flow.jsx'
+
+/**
+ * HtmlFlow — safely render HTML stored in a variable
+ *
+ * Single input: `variable` (name of runner context variable holding HTML).
+ * The variable's value is sanitized using custom DOM filtering and rendered directly
+ * in the preview (not inside an iframe).
+ */
+
+const HtmlFlow = flow((props, ref) => {
+ const { onPop, onUpdate, onPlay, onStop, isPlaying, data, clients } = props
+
+ useImperativeHandle(ref, () => ({
+ onSerialize: () => {
+ return JSON.stringify([data?.variable, data?.html])
+ },
+ onDeserialize: (data) => {
+ const [variable, html] = data ? JSON.parse(data) : [undefined, undefined]
+ return { variable, html }
+ },
+ onCompile: () => {
+ if (!data || !data.variable) {
+ return ''
+ }
+
+ let html = data.html || ''
+ html = JSON.stringify(html)
+
+ return data.variable + ' = ' + html
+ },
+ onExecute: async (runner) => {
+ if (data && data.variable) {
+ let context = runner.getContext()
+ if (context[data.variable]) {
+ onUpdate({
+ ...data,
+ html: context[data.variable]
+ })
+ } else {
+ return runner.run()
+ }
+ }
+ }
+ }), [data])
+
+ const onChangeVariable = (variable) => onUpdate({ ...data, variable })
+
+ const sanitizedHtml = (() => {
+ const dirty = String(data?.html || '')
+ if (!dirty) return ''
+
+ // Custom sanitization for iframes - more permissive than DOMPurify
+ const tempDiv = document.createElement('div')
+ tempDiv.innerHTML = dirty
+
+ // Remove potentially dangerous elements
+ const dangerousElements = tempDiv.querySelectorAll('script, object, embed, form, input, button')
+ dangerousElements.forEach(el => el.remove())
+
+ // Clean up iframe attributes - only keep safe ones
+ const iframes = tempDiv.querySelectorAll('iframe')
+ iframes.forEach(iframe => {
+ // Remove potentially dangerous attributes
+ const allowedAttrs = ['src', 'width', 'height', 'frameborder', 'allowfullscreen', 'allow', 'sandbox']
+ const attrsToRemove = []
+
+ for (let attr of iframe.attributes) {
+ if (!allowedAttrs.includes(attr.name)) {
+ attrsToRemove.push(attr.name)
+ }
+ }
+
+ attrsToRemove.forEach(attr => iframe.removeAttribute(attr))
+
+ // Ensure src starts with https: or is a relative URL
+ const src = iframe.getAttribute('src')
+ if (src && !src.startsWith('https:') && !src.startsWith('/') && !src.startsWith('./')) {
+ iframe.removeAttribute('src')
+ }
+ })
+
+ return tempDiv.innerHTML
+ })()
+
+ return (
+ <>
+