Skip to content

Without Tailwind

How midcode styles a project that has no Tailwind 4: mid: utility classes on the element, and a midcode.css file in your project with their plain CSS.

View as Markdown

You don’t need Tailwind to style a project in midcode. In a project with plain CSS, CSS modules, Sass, Bootstrap or Tailwind 3, the right panel works the same, and what it writes is a utility class of midcode’s own: mid:p-6, mid:md:flex, mid:hover:bg-[#111]. midcode turns those classes into plain CSS itself, in a file called midcode.css that lives in your project.

Nothing is installed in your project and your own classes and stylesheets are never touched. midcode carries the Tailwind 4 compiler inside the app and uses it for the mid: classes only. How it decides a project goes this way is in Tailwind CSS.

The syntax

A mid: class is a Tailwind 4 utility with the prefix first: mid:<variant>:<utility>.

ClassWhat it does
mid:p-624 px of padding.
mid:md:p-416 px of padding from 768 px up.
mid:hover:bg-[#111]A background on hover.
mid:text-[80px]Any value, in brackets.
mid:bg-brandA color of your theme.
mid:leadA text style of your theme.
mid:group-hover/card:underlineA state of a component, on an element inside it.
mid:data-[variant=ghost]:bg-transparentA variant of a component.

Everything Tailwind CSS says about breakpoints, states, variants and where a class can be written holds here, with mid: in front of each class.

Your first style edit

Nothing is added to a project until you change a style, insert something or edit the theme. The first time, midcode sets the project up and then makes your edit:

  1. It creates midcode.css next to your app’s entry, with the CSS of the mid: classes already in the code (none, usually).

  2. It adds one import of that file to the entry.

  3. It creates .midcode/theme.css, an empty theme.

  4. It writes your class.

A message tells you what happened: “midcode added midcode.css to the project and imported it in layout.tsx: the styles you make go there.”

app/layout.tsx
 import type { Metadata } from 'next' import './globals.css'+import './midcode.css'

The import and the theme file are one undoable step, listed in Publish as “Import midcode.css” and “Add .midcode/theme.css”. midcode.css itself is outside the undo history, because it’s rewritten all the time. In Publish, midcode.css is ticked and .midcode/theme.css is not, like every file under .midcode/: tick it if midcode.css is ever built somewhere other than your Mac. midcode also adds a “Styles” section to .midcode/README.md that explains the classes to an agent working in the project without midcode.

Where midcode.css goes

Projectmidcode.cssImported in
Next.js, App Routerapp/ or src/app/The root layout.
Next.js, Pages Routerpages/ or src/pages/_app.
React Router, Remixapp/root.tsx.
ViteNext to the entryThe module index.html loads, src/main.tsx for instance.
SvelteKitsrc/routes/+layout.svelte. midcode creates it when there is none.
Astrosrc/The frontmatter of every layout in src/layouts, or of every page when there are no layouts.

In any other project midcode looks for src/main, src/index or src/entry-client. When it finds no entry, it still creates midcode.css (in src/, or at the root) and tells you to import it yourself: “midcode added src/midcode.css but couldn’t tell where to import it. Import it in your app’s entry so its styles show.”

Other kinds of projectNext release

From the next release, midcode sets up these projects too. A page or a layout written in HTML gets a <link> at the end of its <head>, indented like the line above it.

Projectmidcode.cssLinked from
Plain HTMLThe site’s rootEvery .html page, by a relative path: href="./midcode.css".
NuxtNext to app.vueAn import in its <script setup>.
Shopify themeassets/layout/theme.liquid, with the theme’s own stylesheet tag.
Rails, Laravelpublic/Every layout: href="/midcode.css".
Hugostatic/Every layout, the same way.
Jekyll, PHPThe folder that’s servedEvery layout, the same way.
Eleventypublic/, when the site copies it to its rootEvery layout, the same way.
FlaskIts static/ folderEvery layout: href="/static/midcode.css".
DjangoThe first folder of STATICFILES_DIRSEvery layout, under your STATIC_URL.
WordPress themeThe theme’s folderIts header, through get_theme_file_uri().
Angularpublic/src/index.html.
layouts/_default/baseof.html
  <link rel="stylesheet" href="/css/site.css">
  <link rel="stylesheet" href="/midcode.css">
</head>
layout/theme.liquid
  {{ 'midcode.css' | asset_url | stylesheet_tag }}
</head>

A “layout” here is any template that closes a <head>. Two cases are left to you:

  • Where midcode can’t tell which folder a stack serves as it is (a whole WordPress install, a Django project with no STATICFILES_DIRS), it creates the file and you link it.

  • A Laravel or Rails app with Vite in its package.json is treated as a Vite project. midcode looks for a JavaScript entry there, and when it finds none it creates midcode.css at the project’s root and leaves bringing it into the site to you.

How these sites are edited at all is in Sites a server renders.

What midcode writes

Take a heading with a size, another size from 768 px up, and a color on hover. In your markup that is three classes, next to the one it had:

app/page.tsx
-<h1 className="title">Hello</h1>+<h1 className="title mid:text-[80px] mid:md:text-[56px] mid:hover:text-[#ff5b2e]">Hello</h1>

And midcode.css gets their rules. This is the file, up to the reset that closes it (described below):

app/midcode.css
/*
 * midcode.css: written by midcode (https://midcode.app) from the "mid:" classes in this project's code.
 * Don't edit it by hand: it's rewritten whenever those classes change. The theme is in .midcode/theme.css.
 */
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
@layer mid-theme, mid-base, mid-components, mid-utilities;
@layer mid-utilities {
  .mid\:text-\[80px\] {
    font-size: 80px !important;
  }
  @media (hover: hover) {
    .mid\:hover\:text-\[\#ff5b2e\]:hover {
      color: #ff5b2e !important;
    }
  }
  @media (width >= 48rem) {
    .mid\:md\:text-\[56px\] {
      font-size: 56px !important;
    }
  }
}

A class that uses the scale or the theme brings its variable, in a layer of its own. mid:p-6 adds:

CSS
@layer mid-theme {
  :root, :host {
    --mid-spacing: 0.25rem;
  }
}
@layer mid-utilities {
  .mid\:p-6 {
    padding: calc(var(--mid-spacing) * 6) !important;
  }
}

The file holds exactly the rules of the mid: classes found in your code. Take the last use of a class out and its rule goes with it.

Your own CSS stays yours

  • Only mid: classes are read. A class of yours called .flex, .container or Bootstrap’s .p-3 is never compiled, changed or removed. To the panel, your classes are opaque: a value that comes from your stylesheet shows on the canvas, and changing it in the panel adds a mid: class over it.

  • Every declaration is !important. An edit made in midcode has to win over the rule your CSS already has for that element.

  • The layers have their own names. mid-theme and mid-utilities can’t mix with layers of yours called base or utilities, or with Tailwind 3’s @layer directives.

  • Your site isn’t reset. midcode.css brings no global reset: your headings, links and margins look as they did.

What you insert

Tailwind’s utilities assume a reset. Since your site doesn’t get one, what midcode itself inserts (anything from Insert, and its own components) carries the class mid-base on its root, and midcode.css ends with a small reset scoped to that class: no default margins, unstyled links, lists and buttons, box-sizing: border-box. Those rules are not !important, so every utility still wins over them.

A section from the Insert panel is written like this:

TSX
<section className="mid-base mid:py-24 mid:px-6">
  <h2 className="mid:text-4xl mid:font-semibold">Title</h2>
  <p className="mid:mt-4 mid:text-neutral-600">Text</p>
</section>

How midcode.css stays up to date

While the project is open in midcode, the file follows the code:

  • Before each edit is written, the new classes’ CSS goes into the file first, so the page never shows a class without its style.

  • After each edit and each ⌘Z, it’s rebuilt from what the code holds now.

  • When anything else changes the code (your editor, an agent, a branch switch), a watcher rebuilds it a moment later. It also rebuilds when .midcode/theme.css changes.

  • When the project opens, it’s brought up to date.

midcode looks for mid: classes in .js, .jsx, .ts, .tsx, .mjs, .cjs, .svelte, .astro, .vue, .html, .md and .mdx files, and from the next release also in templates (.liquid, .php, .erb, .ejs, .twig, .njk, .hbs and the like). It skips node_modules, .git and build folders such as .next, dist, build and out.

midcode.css shows in Publish as one entry, “Styles written by midcode (midcode.css)”, however many times it was rewritten. Publish it with your site: the site needs it.

When the project isn’t open in midcode (your production build, CI, an agent writing mid: classes by hand), the midcode package builds the same file.

Tailwind 3

A Tailwind 3 project goes this way too. midcode doesn’t rewrite Tailwind 3’s classes and the panel doesn’t read them. It writes mid: classes beside them, and since those are !important, what you set on the canvas wins:

src/components/Hero.jsx
-<section className="py-16 bg-white">+<section className="py-16 bg-white mid:py-24">

Limits

  • Because the rules are !important, your own CSS can’t override a mid: class. Remove the class, or change it in midcode.

  • Hover styles sit inside @media (hover: hover), as in Tailwind 4: they don’t apply on touch screens.

  • A class name put together at runtime ('mid:p-' + size) isn’t found, so it gets no CSS. Write classes out whole.

  • Files over 2 MB aren’t read.

  • A theme that doesn’t compile (a typo while you’re editing it) keeps the last midcode.css until it’s fixed.

  • Tried with Next.js, Vite, Vite with Tailwind 3 and Astro 7 (a layout with no frontmatter gets one for the import).

Troubleshooting

A style I changed doesn’t show. Check that midcode.css is imported in your app’s entry, or linked from the page. midcode adds the import when it sets the project up and looks again at every style edit, so a page or a layout you added later gets its link with your next edit. An entry midcode couldn’t find needs the import by hand.

I moved midcode.css. midcode looks for it next to the entry, then in src/app/, app/, src/, src/routes/ and the project’s root. Anywhere else it won’t find it: the next style edit creates a second file next to the entry, while your import still points at the one you moved. Keep the file in one of those places.

I deleted midcode.css. The next style edit creates it again from the classes in the code.

A class I wrote by hand has no effect. With the project open in midcode it’s picked up within a moment. Otherwise run npx midcode: see The midcode package.

git reports a conflict in midcode.css. The file is generated: keep either side, then let midcode or npx midcode rewrite it.