Malevich

AI-Things / Prompts / Prompt/

Refactor to Malevich

Convert an existing piece of UI code — vanilla HTML/CSS, Tailwind, Bootstrap, or another design system — into Malevich-conformant markup with no loss of behavior or accessibility.

transformation · code → component · updated 2026-05-21

Use case: When you have working code that isn't Malevich and you want to bring it into the system without rewriting it from scratch.

When to use

You have a fragment of working code — anything from a Tailwind login form to a Bootstrap modal — and you want a Malevich version that behaves identically but follows the system. Use this for single-component or single-screen-fragment refactors. For full-page rewrites or system-wide migrations, plan a multi-step migration with the malevich-refactor skill, not a single prompt invocation.

The prompt

Fill in the placeholders and send the text below.

You are working in the Malevich design system. Before answering, read:

  • llm-wiki/architecture.md
  • llm-wiki/glossary.md
  • llm-wiki/playbook/semantic-html.md

Then load the malevich-refactor skill if you haven't already.

I have the following code:

Source code:

{{code}}

Source framework or system: {{source_system}}

Refactor this into Malevich. Follow these rules:

  1. Preserve behavior. Visual appearance may differ slightly to match Malevich tokens, but interactive behavior (focus, keyboard, form submission, dismissal) must be identical or better.
  2. Preserve identifiers. Keep IDs, data attributes, and identifier classes (.checkout-form, .user-card). Only change visual class names.
  3. Use existing components first. If the code is a button, produce a Malevich Button. Don't invent a new component because the source had custom styling.
  4. Standard HTML, no custom elements. Malevich components are semantic elements with BEM classes — no <m-*> tags, no Shadow DOM (ADR-0004). Modals use the native <dialog> element.
  5. One-to-one mapping where possible. A <div class="modal"> becomes a <dialog class="dialog">; don't restructure unnecessarily.
  6. Identity vs presentation. Map a status/role to a BEM variant (.alert.-warning); map a visual treatment or behavior to a data-{category} modifier (data-surface, data-effect, data-behavior), checked against the component's row in modifiers/applicability.json.
  7. No raw values. Every color, size, and spacing references a var(--token) — semantic (tier-2) or component-specific (tier-3), never tier-1 --palette-* / --scale-*. If a value has no clean equivalent, use the closest existing token and flag it.

Output format:

  1. Inventory — UI elements found in the source and the Malevich component each maps to. Format: <source identifier or description> → <Malevich component> (.<class>)
  2. Refactored code — the rewritten markup, with CSS inside @layer malevich.components.
  3. Diff summary — three bullet lists: Visual changes, Structural changes, Behavioral changes. Keep them short — a long list means you've gone past refactor into rewrite.
  4. Open questions for me — anything you weren't sure about.

Do not rewrite the source from scratch. If you find yourself producing markup that no longer resembles the original, stop and ask whether a rewrite is what I want.

Variables

Placeholder What to fill in
{{language}} The fence language: html, jsx, vue, astro.
{{code}} The source code to refactor. Keep it focused — one screen region per invocation.
{{source_system}} Where the code came from: Tailwind, Bootstrap 5, Material UI, vanilla, shadcn/ui, etc. Tells the agent which idioms to translate.

Example input

Source: a Tailwind notification banner.

<div class="bg-yellow-100 border-l-4 border-yellow-500 p-4 flex items-start gap-3">
  <svg class="w-5 h-5 text-yellow-700 flex-shrink-0"><!-- ... --></svg>
  <div class="flex-1">
    <h3 class="font-semibold text-yellow-900">Heads up</h3>
    <p class="text-sm text-yellow-800">Your trial ends in 3 days.</p>
  </div>
  <button class="text-yellow-700 hover:text-yellow-900" aria-label="Dismiss">✕</button>
</div>

Source system: Tailwind.

Example output

Inventory:

outer container (banner)  → Malevich Alert (display element) (.alert.-warning)
icon                      → icon-pack glyph                  (i.icon[data-icon])
title                     → Alert title                      (.alert__title)
body                      → Alert body                       (.alert__body)
dismiss affordance        → dismissible behavior modifier    (data-behavior)

Refactored code:

<aside class="alert -warning" data-behavior="dismissible">
  <i class="alert__icon icon" data-icon="warning" aria-hidden="true"></i>
  <div>
    <p class="alert__title">Heads up</p>
    <p class="alert__body">Your trial ends in 3 days.</p>
  </div>
</aside>

No component CSS needed — the Alert element ships all required styles. Status is the -warning variant. Dismissibility is the data-behavior="dismissible" modifier; Alert's applicability row lists dismissible, and the runtime wires the close affordance — so a separate hand-rolled dismiss button is unnecessary.

Diff summary:

Open questions for me:

  1. The original used <h3> for the title; I used <p class="alert__title"> to avoid injecting a heading level mid-flow. If this banner is a landmark that needs a heading, tell me the right level.
  2. Should this be announced immediately by screen readers? If yes, swap <aside> for role="alert" — reserve that for urgent messages.
  3. The icon uses the canonical pack name warning. If your registered pack names it differently, tell me the pack.

Tips for a good refactor

Pairs with