# 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.

- Page: https://midcode.app/docs/styling/without-tailwind
- From the midcode docs. Every page as Markdown: https://midcode.app/llms.txt

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](https://midcode.app/docs/styling/tailwind.md).

## The syntax

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

| Class | What it does |
| --- | --- |
| `mid:p-6` | 24 px of padding. |
| `mid:md:p-4` | 16 px of padding from 768 px up. |
| `mid:hover:bg-[#111]` | A background on hover. |
| `mid:text-[80px]` | Any value, in brackets. |
| `mid:bg-brand` | A color of [your theme](https://midcode.app/docs/styling/theme.md). |
| `mid:lead` | A text style of your theme. |
| `mid:group-hover/card:underline` | A state of a component, on an element inside it. |
| `mid:data-[variant=ghost]:bg-transparent` | A variant of a component. |

Everything [Tailwind CSS](https://midcode.app/docs/styling/tailwind.md) 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."

```diff title="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](https://midcode.app/docs/publish/publish.md) 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

| Project | midcode.css | Imported in |
| --- | --- | --- |
| Next.js, App Router | `app/` or `src/app/` | The root `layout`. |
| Next.js, Pages Router | `pages/` or `src/pages/` | `_app`. |
| React Router, Remix | `app/` | `root.tsx`. |
| Vite | Next to the entry | The module `index.html` loads, `src/main.tsx` for instance. |
| SvelteKit | `src/routes/` | `+layout.svelte`. midcode creates it when there is none. |
| Astro | `src/` | 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 project (next 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.

| Project | midcode.css | Linked from |
| --- | --- | --- |
| Plain HTML | The site's root | Every `.html` page, by a relative path: `href="./midcode.css"`. |
| Nuxt | Next to `app.vue` | An import in its `<script setup>`. |
| Shopify theme | `assets/` | `layout/theme.liquid`, with the theme's own stylesheet tag. |
| Rails, Laravel | `public/` | Every layout: `href="/midcode.css"`. |
| Hugo | `static/` | Every layout, the same way. |
| Jekyll, PHP | The folder that's served | Every layout, the same way. |
| Eleventy | `public/`, when the site copies it to its root | Every layout, the same way. |
| Flask | Its `static/` folder | Every layout: `href="/static/midcode.css"`. |
| Django | The first folder of `STATICFILES_DIRS` | Every layout, under your `STATIC_URL`. |
| WordPress theme | The theme's folder | Its header, through `get_theme_file_uri()`. |
| Angular | `public/` | `src/index.html`. |

```html title="layouts/_default/baseof.html"
  <link rel="stylesheet" href="/css/site.css">
  <link rel="stylesheet" href="/midcode.css">
</head>
```

```liquid title="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](https://midcode.app/docs/frameworks/server-templates.md).

## 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:

```diff title="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):

```css title="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](https://midcode.app/docs/editor/insert.md), 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](https://midcode.app/docs/styling/package.md) 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:

```diff title="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](https://midcode.app/docs/styling/package.md).

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