Skip to content

Insert

The Insert panel adds frames, text, media, embeds, forms, sections, components and icons to a page, written as plain code in your own files.

View as Markdown

The Insert panel is where new elements come from. Click the plus button (“Insert”) in the toolbar at the bottom of the canvas and the panel opens over the left panel, with its search field ready. Close it with the ✕ in its header, or Esc once nothing is selected, and the tab you were on comes back.

Everything in the panel is static markup with utility classes, written into the file of the page (or the component) you’re on. One insert is one ⌘Z step and one entry in Publish, with any file it brings along.

Add something

  1. Open the panel and pick a tile.

  2. Click it. With an element selected, the new one goes at the selection. With nothing selected, it goes at the end of the page. The line under the search field says which: “Click adds it at the selection; drag to place it” or “Click adds it at the end of the page; drag to place it”.

  3. Or drag it onto a breakpoint. The frame under the pointer draws where it would land: a line between two elements, or a box around the one it would go into.

The new element is selected as soon as the page shows it, so you can style it straight away in the style panel.

Search looks at names, descriptions and keywords (“slider” finds Carousel and Slideshow). Enter adds the first match, the one with the ring. With two letters or more the list also offers “Search icons”, which opens the icon browser on those words.

Shortcuts

Each of these adds the item at the selection, like a click on its tile.

KeyAdds
FFrame
SStack
TText
⇧GGrid
⇧IImage (asks for a file first)
⇧VVideo (asks for a file first)

In a Next.js App Router project, F on the page canvas is the draw tool of the free canvas instead: you draw the frame where you want it. Inside a component, and in every other kind of project, F inserts the Frame.

What’s in the panel

CategoryItems
BasicsFrame, Stack, Row, Grid, Text, Heading, Button, Link, Divider, Spacer
MediaImage, Video, Audio, Icon, Sticker
EmbedsYouTube, Vimeo, Spotify, SoundCloud, Google Maps, Embed
FormsContact form, Newsletter, Input, Email, Phone, Textarea, Select, Checkbox, Radio group, Submit button
SectionsNavbar, Hero, Hero with image, Logo cloud, Features grid, Feature with image, Stats, Testimonials, Pricing, FAQ, Call to action, Contact, Footer
ComponentsCarousel, Slideshow, Ticker, Tabs, Cookie banner, Language switcher, Shader gradient

Basics

Small pieces in one neutral look: they take your site’s text color and font, and draw surfaces and lines from it (bg-current/5, border-current/10).

TSX
<div className="flex flex-col gap-4">
  <div className="h-24 rounded-2xl bg-current/5" />
  <div className="h-24 rounded-2xl bg-current/5" />
</div>

That’s a Stack. Buttons are written with bg-neutral-900 text-white; if your theme has the colors primary and primary-foreground (or foreground and background), midcode writes those instead.

Media

Image, Video and Audio ask for a file from your Mac. midcode copies it into your project’s public folder (public/images, public/videos, public/audio) and writes the element that shows it:

TSX
<img src="/images/hero-photo.jpg" alt="Hero photo" className="w-full min-w-0 rounded-2xl object-cover" />

The alt text starts as the file’s name in words. If the same file is already in that folder it’s used again; a different file with the same name gets a number (hero-photo-1.jpg). Files dropped from Finder onto a breakpoint are inserted the same way. Replacing media and pasting images are on Text, images and video.

Icons and stickers

The Icon and Sticker tiles open a browser: choose a set (Phosphor, Lucide, Heroicons, Material Symbols, Tabler, Feather, Remix Icon, Material Design Icons, Simple Icons, SVG Logos; for stickers Fluent Emoji, Noto Emoji, Twemoji, OpenMoji), a style when the set has several, search, then click or drag one. The sets come from the Iconify API and are kept on your Mac once seen, so the first time needs a connection.

What an icon becomes depends on your package.json:

  • If the project has the set’s React package (lucide-react, @phosphor-icons/react, @heroicons/react, @tabler/icons-react), midcode imports the component. The browser’s footer names the package when that’s the case.

  • Otherwise it writes the icon inline, as an <svg> that takes the text color.

With lucide-react installed
import { Heart } from 'lucide-react'

<Heart className="size-6" aria-hidden="true" />
Without the package
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" className="size-6" aria-hidden="true">...</svg>

A Lucide or Phosphor name that would shadow something in the page (Image, Link, Map) is imported under its Icon alias (ImageIcon).

A sticker is a colored SVG. It’s saved as a file and shown by an <img>:

TSX
<img src="/stickers/fluent-emoji-flat-rocket.svg" alt="" width="96" height="96" className="size-24" />

The file goes to public/stickers/. Every SVG midcode writes is cleaned first, so nothing in it can run or load from elsewhere: no scripts, no event handlers, no links to other sites.

Embeds

An embed tile writes an <iframe> with a working example link, so you see a real player at once:

TSX
<iframe
  src="https://www.youtube.com/embed/k3BPZ87BQmg"
  title="YouTube video"
  className="aspect-video w-full rounded-xl"
  loading="lazy"
  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
  allowFullScreen
  referrerPolicy="strict-origin-when-cross-origin"
/>

Select it and paste your own link in the right panel, under “Embed” → “Link”. You can paste a share link, an embed address, a whole <iframe> embed code, or a place name for a map. midcode turns it into the address the player needs, and changes the title, the permissions and the size classes when the new link is another kind of player. Loom and Figma links are recognized too. See element settings.

Forms

Contact form and Newsletter are whole forms; the rest are single fields with their label. A form is written with method="post" and no action: set where it sends in the right panel (“Form” → “Action”), and add fields there with “Add field”.

A second copy never collides with the first: ids the file already uses get a number (contact-form-name becomes contact-form-name-2, and its label’s htmlFor follows), and so do field names taken inside the same form.

Sections

Whole page blocks, shown in the panel as a live, scaled render of what they write. The ones with a picture use a neutral placeholder, written once to public/midcode/placeholder.svg.

Components

The Components category is interactive: a carousel, a slideshow, a ticker, tabs, a cookie banner, a language switcher, an animated gradient. These need code that runs, so midcode writes each one’s source into your project the first time you use it, and imports it:

app/layout.tsx
 import './globals.css'+import { CookieBanner } from '@/components/midcode/CookieBanner'  export default function RootLayout({ children }: { children: React.ReactNode }) {   return (     <html lang="en">-      <body>{children}</body>+      <body>+        {children}+        <CookieBanner />+      </body>     </html>   ) }
  • The file goes in components/midcode/, next to your other sources: src/components/midcode/ when the project keeps its code in src/, app/components/midcode/ in React Router and Remix.

  • It’s a .tsx file when the project has a tsconfig.json, and a plain .jsx file (same code, types removed) when it doesn’t.

  • It’s written once. If the file is already there, midcode uses it as it is and never writes over it: from then on it’s your code.

  • The import uses your tsconfig.json or jsconfig.json path alias when one covers that folder (@/components/...), a relative path otherwise. If the file already has something called Carousel, the import is Carousel as MidcodeCarousel.

Their options (autoplay, arrows, speed, colors) show as typed controls under Props when you select one. The Language switcher is written with your project’s languages already in its props, when midcode finds them (see Languages).

Where it lands

You do thisThe new element goes
Click, with a container selectedLast inside it. Containers are div, section, main, article, header, footer, nav, aside, form, figure, ul, ol, li, fieldset, details and dialog.
Click, with anything else selectedRight after it. Next to a component instance, never into the component’s file.
Click a section, a Ticker or a Shader gradientAfter the page’s top-level block that holds the selection.
Click, with nothing selectedAt the end of the page: last inside the element the page returns, or inside its <main>.
Add a Cookie bannerLast inside the <body> of the root layout: the layout.tsx nearest the page in the App Router, root.tsx in React Router and Remix. In the Pages Router it goes at the end of the page.
DragWhere the line or the box shows.
Drop on the empty canvasIt floats there, in Next.js App Router projects. See The free canvas.

A single element added with nothing selected (a form, an embed, an image) would sit flush against the page’s edge, so it comes inside a block of its own:

TSX
<section className="mx-auto w-full max-w-6xl px-6 py-12">
  <p className="leading-relaxed">Say what matters in a sentence or two, and keep it easy to read.</p>
</section>

In component mode everything goes into the component’s file; with nothing selected, last inside its root. A Cookie banner belongs to the site, so there midcode answers “This goes on the page: go back to the page to add it”.

To add one of your own components, drag it from the Assets tab. midcode writes <Card /> and its import.

What midcode writes

  • The code goes in with the indentation of the lines around it, in the file’s own unit (two spaces, four, tabs).

  • Imports go after the file’s last import (after 'use client' when there are none), with the quotes and semicolons the file already uses. A named import from a module the file already imports from joins that line.

  • A page that returns a single component (return <Home />) gets a fragment around it and the new element.

  • Nothing is written if the result wouldn’t parse. You get “Couldn’t insert it: the code wouldn’t parse” and the file stays as it was.

  • Files that come with the insert (a component, a sticker, the placeholder) are part of the same step: ⌘Z takes the element out and deletes the files it created. If another file has started using one of them since (a second page imports the Carousel), that step can’t be undone, and midcode says which file uses it.

Projects without Tailwind 4

In a project that midcode styles itself, the same snippets are written with the mid: prefix, and their root gets mid-base, which scopes a small reset to what midcode inserted:

TSX
<p className="mid-base mid:leading-relaxed">Say what matters in a sentence or two, and keep it easy to read.</p>

The components written to components/midcode/ are prefixed the same way. See Without Tailwind.

Other frameworks

In Svelte files the snippets are written as HTML: class and for, lowercase attributes, no self-closing <div />. Icons are always inline SVG there, and files go to static/ in SvelteKit. The Components category is React only: on a Svelte page its tiles are dimmed and say “Needs a React page”.

Vue, Astro, HTML and templatesNext release

The next release inserts into .vue and .astro files, plain HTML and server templates the same way as into Svelte. Three things are different there:

  • An insert that needs an import (an icon from a package, one of your components) gets it in a .vue file (in its <script setup>) and in an .astro file (in its frontmatter), created when the file has none. In a Nuxt project nothing is imported for a component under components/, which Nuxt finds by itself. It’s still refused in a Vue component written with the Options API, in plain HTML and in server templates: “This needs an import, which midcode can’t add to Hero.vue yet. Add it in the code.”

  • In JSX that isn’t React (Solid, Preact, Qwik) the snippets follow the file and write class and for. midcode’s own components are React, so without react in package.json they’re refused: “This component needs a React page”.

  • Nothing is inserted into content that comes from a Markdown file (a post in Hugo, Jekyll or Eleventy). Select an element of the template around it instead.

Limits

  • The interactive components are React components. There are no Svelte or Vue versions.

  • A click needs a place to go. On a page whose file midcode can’t add to by itself it says “Select an element first: the new one goes next to it”. If it can’t tell what a page file renders (it returns a condition, for instance), it asks you to select an element on the canvas first.

  • A section goes among the page’s top-level blocks. When the page’s shape can’t be read, it goes next to the selection instead.

  • Icons and stickers can’t be browsed offline until their set has been loaded once.

  • In projects midcode only shows (see Supported stacks), the tiles are disabled.