Skip to content
HomePagesHomePages template kit
Menu

template-kit/no-inline-style

The template-kit/no-inline-style authoring rule — what it enforces, why, and how to fix it.

No inline style= in server-rendered section JSX. Islands are exempt — but an island is not exempt from no-hex.

Whether a file is server-rendered or an island is decided per file, by the "use client" directive — see server vs client. On an island this rule installs no visitors at all.

In a server-rendered file it reports any JSX attribute named style, on any element. The value is never inspected: a static object, a computed one, a spread, a string — all the same. There is no “but this one is fine” case in a server-rendered file.

The island exemption does not extend to colour. no-hex reads inside style values and has no island exemption at all, so this still fails on a "use client" file:

"use client";
export default function Badge() {
return <div style={{ color: "#ff0000" }} />; // template-kit/no-hex
}

Exempt from this rule; still a hard-coded colour.

Three concrete failures, all of them server-render concerns:

  • It bypasses the cascade. An inline style is the highest-specificity declaration short of !important, so a template’s theme can no longer restyle the section. The section stops being portable.
  • It skips Tailwind’s responsive prefixes. style={{ padding: 16 }} has no breakpoint form; there is no way to say “16 on mobile, 48 on desktop” in it. Utilities have exactly that (p-4 lg:p-12), which is why the layout ladder lives in classes.
  • It churns per-call identity that the editor’s hash-based diff cannot dedupe — the editor re-renders the section on every keystroke, and a fresh style object each render is work it cannot skip.

An island computing a transform from live pointer state has none of these problems: it runs in the browser, it is not part of the cascade the theme is styling, and that is precisely what an island is for. So it is exempt.

Use Tailwind utility classes. For a value that only exists at runtime, move the markup into a "use client" island, where style is allowed.

import { Section } from "@homepages/template-kit";
import type { Props } from "./schema.js";
export function Renderer({ slots }: Props) {
return (
<Section>
<div style={{ padding: 16, display: "flex", gap: 8 }}>
<h2>{slots.headline}</h2>
</div>
</Section>
);
}
import { Section } from "@homepages/template-kit";
import type { Props } from "./schema.js";
export function Renderer({ slots }: Props) {
return (
<Section>
<div className="flex gap-2 p-4">
<h2>{slots.headline}</h2>
</div>
</Section>
);
}

The runtime-value case — a transform driven by live state — has no utility form, and is the case the island exemption exists for:

sections/hero/Parallax.tsx
"use client";
import { useState } from "react";
import type { ReactNode } from "react";
export default function Parallax({ children }: { children: ReactNode }) {
const [offset, setOffset] = useState(0);
return (
<div
onPointerMove={(e) => setOffset(e.clientX / 40)}
style={{ transform: `translateX(${offset}px)` }}
>
{children}
</div>
);
}
  • Server vs client — the island exemption, and the one rule that does not take it.
  • Theme and CSS — the token utilities and the breakpoint ladder.