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.
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
Open the panel and pick a tile.
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”.
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.
| Key | Adds |
|---|---|
| F | Frame |
| S | Stack |
| T | Text |
| ⇧G | Grid |
| ⇧I | Image (asks for a file first) |
| ⇧V | Video (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
| Category | Items |
|---|---|
| Basics | Frame, Stack, Row, Grid, Text, Heading, Button, Link, Divider, Spacer |
| Media | Image, Video, Audio, Icon, Sticker |
| Embeds | YouTube, Vimeo, Spotify, SoundCloud, Google Maps, Embed |
| Forms | Contact form, Newsletter, Input, Email, Phone, Textarea, Select, Checkbox, Radio group, Submit button |
| Sections | Navbar, Hero, Hero with image, Logo cloud, Features grid, Feature with image, Stats, Testimonials, Pricing, FAQ, Call to action, Contact, Footer |
| Components | Carousel, 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).
<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:
<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.
import { Heart } from 'lucide-react'
<Heart className="size-6" aria-hidden="true" /><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>:
<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:
<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:
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 insrc/,app/components/midcode/in React Router and Remix.It’s a
.tsxfile when the project has atsconfig.json, and a plain.jsxfile (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.jsonorjsconfig.jsonpath alias when one covers that folder (@/components/...), a relative path otherwise. If the file already has something calledCarousel, the import isCarousel 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 this | The new element goes |
|---|---|
| Click, with a container selected | Last 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 selected | Right after it. Next to a component instance, never into the component’s file. |
| Click a section, a Ticker or a Shader gradient | After the page’s top-level block that holds the selection. |
| Click, with nothing selected | At the end of the page: last inside the element the page returns, or inside its <main>. |
| Add a Cookie banner | Last 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. |
| Drag | Where the line or the box shows. |
| Drop on the empty canvas | It 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:
<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:
<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
.vuefile (in its<script setup>) and in an.astrofile (in its frontmatter), created when the file has none. In a Nuxt project nothing is imported for a component undercomponents/, 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
classandfor. midcode’s own components are React, so withoutreactinpackage.jsonthey’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.