# How Instatic's Super Import Converts Raw HTML/CSS into Editable Nodes

> Discover how Instatic's Super Import transforms raw HTML CSS into editable nodes. Learn about its deterministic pipeline for parsing, stripping unsafe content, and mapping elements.

- Repository: [CoreBunch/Instatic](https://github.com/CoreBunch/Instatic)
- Tags: internals
- Published: 2026-07-30

---

**Instatic's Super Import uses a deterministic pipeline in [`src/core/htmlImport/walkAndMap.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/htmlImport/walkAndMap.ts) to parse raw HTML, strip unsafe content through `stripUnsafe`, recursively map DOM elements to `PageNode` objects via `walkAndMap`, and extract CSS into the `styleCss` field for the editor's Style panel.**

Instatic's visual editor manipulates a structured node tree to enable real-time page editing. The **Super Import** feature bridges static HTML documents and this editable ecosystem by transforming raw markup into native `PageNode` objects that the editor can manipulate immediately. According to the CoreBunch/Instatic source code, this conversion happens through a single public API that performs sanitization, parsing, and tree mapping in one atomic pass.

## The Five-Stage Import Pipeline

The `importHtml` function exported from [`src/core/htmlImport/walkAndMap.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/htmlImport/walkAndMap.ts) processes HTML strings through five deterministic stages that ensure safe, accurate conversion to editable nodes.

### Stage 1: Parsing the Raw Markup

The pipeline begins by invoking `parseHtml` to convert the raw HTML string into a DOM-like tree structure. This initial parse provides a traversable foundation for the sanitization and mapping steps that follow.

### Stage 2: Sanitizing Unsafe Content

Before traversal, the `stripUnsafe` function removes potentially dangerous elements including `<script>` tags, `on*` event attributes, and dangerous URLs. This stage guarantees that imported fragments cannot execute code when rendered in the visual editor, and sets a `stripped` flag in the final result if any content was removed.

### Stage 3: Walking and Mapping to PageNodes

The `walkAndMap` function recursively traverses the sanitized DOM tree, converting each element into a **PageNode** as defined in [`src/core/page-tree/types.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/page-tree/types.ts). During this walk, the implementation extracts:
- **HTML attributes** → stored on `props.htmlAttributes`
- **Inline styles** → converted to camel-case and stored on `inlineStyles`
- **Class names** → transformed into `classIds` for the selector registry
- **Text nodes** → become `base.text` nodes
- **Semantic elements** → images become `base.image`, links become `base.link`, and forms map to corresponding built-in modules

All children are processed recursively, preserving the original document nesting in the resulting node tree.

### Stage 4: Extracting Page-Scoped CSS

While walking the DOM, the importer collects content from inline `<style>` blocks and `<link rel="stylesheet">` references. These styles concatenate into the `styleCss` field of the `ImportResult`, which later persists as a page-scoped stylesheet and appears in the editor's **Style** panel.

### Stage 5: Returning the Import Result

The function returns an `ImportResult` object containing:
- `nodes`: A `Map<string, PageNode>` of all created nodes
- `rootIds`: Array identifiers for top-level nodes (typically the `<body>` element)
- `styleCss`: Concatenated CSS string for style extraction
- `stripped`: Boolean indicating whether unsafe content was removed

## Integration with Editor Architecture

The importer integrates with Instatic's broader architecture through [`src/core/siteImport/htmlPagePlan.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/siteImport/htmlPagePlan.ts), which orchestrates the site-import pipeline. When users trigger imports via the admin interface—handled by [`src/admin/spotlight/commands/importHtml.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/admin/spotlight/commands/importHtml.ts)—the system calls `importHtml(htmlSource)` and commits resulting nodes using standard editor mutations like `insertNode` and `replaceNodeHtml`.

Extracted CSS flows through [`src/core/publisher/cssCollector.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/publisher/cssCollector.ts) to populate the style registry, ensuring that imported designs remain editable alongside natively created content.

## Practical Implementation Example

The following TypeScript demonstrates importing raw HTML and inserting it into the active page tree:

```typescript
import { importHtml } from '@core/htmlImport'
import { mutateActiveTree } from '@core/page-tree'
import { insertNode, addPageStyle } from 'src/admin/pages/site/store/slices/site/helpers'

const rawHtml = `
  <html>
    <head>
      <style>.hero { background:#f0f0f0; }</style>
    </head>
    <body class="hero">
      <h1>Hello world</h1>
      <p data-note="example">A paragraph with <a href="/page">a link</a>.</p>
      <img src="/photo.jpg" alt="Example" />
    </body>
  </html>
`

const { nodes, rootIds, styleCss, stripped } = importHtml(rawHtml)

// Insert each root node into the current page
rootIds.forEach(rootId => {
  const node = nodes[rootId]
  mutateActiveTree(state => {
    insertNode({ parentId: state.activePageId, node })
  })
})

// Persist extracted CSS to the page's style panel
addPageStyle({ pageId: 'current-page-id', css: styleCss })

```

This results in a `base.body` node containing `base.text` nodes for the heading and paragraph, a `base.link` module for the anchor tag, and a `base.image` node for the photograph, with the `.hero` class available in the Style panel for editing.

## Summary

- **Core Conversion**: Instatic's Super Import relies on `importHtml` in [`src/core/htmlImport/walkAndMap.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/htmlImport/walkAndMap.ts) to transform HTML into editable nodes.
- **Safety First**: The `stripUnsafe` function eliminates scripts and event handlers before DOM traversal begins.
- **Node Mapping**: The `walkAndMap` utility converts HTML elements to specific node types (`base.text`, `base.image`, `base.link`) while preserving attributes in `props.htmlAttributes` and styles in `inlineStyles`.
- **CSS Preservation**: Style blocks extract into the `styleCss` field for integration with [`src/core/publisher/cssCollector.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/publisher/cssCollector.ts) and the visual editor's Style panel.
- **Seamless Integration**: The `ImportResult` interface provides `nodes`, `rootIds`, and metadata for immediate insertion via standard mutation APIs like `insertNode`.

## Frequently Asked Questions

### What file contains the main importHtml function?

The core implementation lives in **[`src/core/htmlImport/walkAndMap.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/htmlImport/walkAndMap.ts)**. This file exports the `importHtml` function and contains the `parseHtml`, `stripUnsafe`, and `walkAndMap` utilities that power the conversion process.

### How does Instatic handle unsafe HTML during import?

The `stripUnsafe` function removes all `<script>` tags, `on*` event handlers, and dangerous URLs before the DOM traversal begins. The `ImportResult` returns a `stripped` boolean flag indicating whether unsafe content was detected and removed, ensuring the editing surface remains secure.

### Can imported CSS be edited within the Instatic visual editor?

Yes. The importer extracts CSS from `<style>` tags and external stylesheets into the `styleCss` field, which integrates with **[`src/core/publisher/cssCollector.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/core/publisher/cssCollector.ts)**. This CSS appears in the editor's **Style** panel as page-scoped stylesheets that users can modify alongside Tailwind utilities.

### What node types does the importer create from HTML elements?

The `walkAndMap` function maps standard HTML to specific module types: text nodes become **`base.text`**, images become **`base.image`**, links become **`base.link`**, and the body element transforms into **`base.body`**. Generic containers map to structural nodes while preserving original HTML attributes in `props.htmlAttributes` for complete styling control.