Skip to content

Variables

Turn a component's text, image, link or style into a prop from the canvas, so each use of the component sets its own. The code before and after.

View as Markdown

A variable is a prop of a component that you make from the canvas instead of typing it. A card that always says “Oak House” becomes a card whose title each page sets: you press a plus beside the text, and midcode declares the prop, gives it the text as its default, and makes the markup read it.

Nothing changes on screen when you make one. The value the element had is the prop’s default, so every existing use of the component looks the same until one of them sets its own.

Variables are made in component mode, in React components. From the next release, in Svelte, Vue and Astro components too.

Make a variable

  1. Open the component (double-click an instance, or click it in Assets).

  2. Select an element inside it.

  3. In the right panel, find the property and press its plus, “Make it a variable”. Beside Text, Link, Image and Video the plus is in the section’s header. Beside a style it shows to the left of the row when you point at it.

These are the properties that have one:

PropertyBecomesName it starts with
TextThe element’s texttitle on a heading, label on a button or a link, text elsewhere
LinkIts hreflink
Image, VideoIts srcimage, video
ColorAn inline colorcolor
BackgroundAn inline backgroundColorbackground
PaddingAn inline paddingpadding
GapAn inline gapgap
OpacityAn inline opacityopacity
RadiusAn inline borderRadiusradius

You aren’t asked for a name. If the component already has a prop called title, the new one is title2; rename it afterwards in the Variables window.

Once a property is a variable, its control is replaced by a violet chip with the variable’s name: the value is no longer the component’s to set. Click the chip to edit the variable, or right-click it → “Remove variable”.

Set it where the component is used

Go back to the page (Esc), select an instance of the component, and look under “Props” in the right panel. Each variable is a control of its kind: a text field, an image picker, a color, a number. What you set there is written on that instance:

app/page.tsx
-<Card href="/work/pine" />+<Card href="/work/pine" title="Pine Cabin" image="/images/pine.jpg" radius={24} />

How those controls are chosen is on Components.

The Variables window

The “Variables” button in the bar over the component canvas opens a window with every variable of the component (it shows how many there are). Pick one on the left to:

  • change its Name. The rename follows the prop everywhere: its type, where the component reads it, and every instance that sets it.

  • see its Kind: Text, Number, Color, Image or Link (a prop you wrote by hand can also be Yes / No, Choice or Code).

  • change its Default, the value the component shows until a use sets it.

  • see what it’s Used by: a text, an attribute, a style.

  • Remove variable.

The list is the component’s props, so props you wrote by hand are there too. Props the component only passes on (children, className, style), event handlers and variant are left out.

What midcode writes

Each of these is one edit, and one ⌘Z. Start from this component:

components/Card.tsx
interface CardProps {
  href: string
}

export function Card({ href }: CardProps) {
  return (
    <a href={href} className="block rounded-xl p-6">
      <img src="/images/oak.jpg" alt="" className="w-full" />
      <h3 className="text-xl font-semibold">Oak House</h3>
    </a>
  )
}

A text

Select the heading and press the plus beside Text.

components/Card.tsx
 interface CardProps {   href: string+  title?: string } -export function Card({ href }: CardProps) {+export function Card({ href, title = 'Oak House' }: CardProps) {   return (     <a href={href} className="block rounded-xl p-6">       <img src="/images/oak.jpg" alt="" className="w-full" />-      <h3 className="text-xl font-semibold">Oak House</h3>+      <h3 className="text-xl font-semibold">{title}</h3>     </a>   ) }

An attribute

Select the image and press the plus beside Image. The JSDoc line tells the Props section this string is an image, so instances get a file picker. A color gets @control color, a link @control link.

components/Card.tsx
 interface CardProps {   href: string   title?: string+  /** @control image */+  image?: string } -export function Card({ href, title = 'Oak House' }: CardProps) {+export function Card({ href, title = 'Oak House', image = '/images/oak.jpg' }: CardProps) {   return (     <a href={href} className="block rounded-xl p-6">-      <img src="/images/oak.jpg" alt="" className="w-full" />+      <img src={image} alt="" className="w-full" />       <h3 className="text-xl font-semibold">{title}</h3>     </a>   ) }

A style

Select the card and press the plus beside Radius. A class can’t take a value that’s only known when the component renders, so a style variable is written inline, and the classes that used to set it are removed.

components/Card.tsx
   title?: string   /** @control image */   image?: string+  radius?: number } -export function Card({ href, title = 'Oak House', image = '/images/oak.jpg' }: CardProps) {+export function Card({ href, title = 'Oak House', image = '/images/oak.jpg', radius = 12 }: CardProps) {   return (-    <a href={href} className="block rounded-xl p-6">+    <a href={href} className="block p-6" style={{ borderRadius: radius }}>

The default is the radius the element had, in px. If the element already has a style={{ … }} object, the new key joins it.

Other ways a component takes its props

midcode declares the prop the way the component already works:

  • No TypeScript: there’s no type to add to. The kind goes on the destructured name: { /** @control image */ image = '/images/oak.jpg' }.

  • Props not destructured (function Card(props: CardProps)): the markup reads {props.title ?? 'Oak House'}, and the type’s member carries the default as /** @default 'Oak House' */ so the Props section knows it.

  • No parameter yet (function Card()): midcode adds one, { title = 'Oak House' }: { title?: string }.

Renaming

Renaming title to heading changes the type’s member, the destructured name, every place the component reads it, and title="…" on every instance in the project.

Removing

Removing a variable takes the prop out of the type and the destructuring, takes the attribute off every instance, and writes the default back where the prop was read: {title} is “Oak House” again, and src={image} is src="/images/oak.jpg" again.

A style variable is the exception. The inline style stays, with the default in it (style={{ borderRadius: 12 }}), and the class that was removed is not put back.

Svelte, Vue and AstroNext release

In the next release the plus is there in a .svelte, .vue or .astro component too, and the Variables window works the same. What changes is how each of them writes a prop being read:

SvelteVueAstro
Text<h3>{title}</h3><h3>{{ title }}</h3><h3>{title}</h3>
Attributesrc={image}:src="image"src={image}
Stylestyle:border-radius="{radius}px":style="{ borderRadius: radius + 'px' }"style={{ borderRadius: `${radius}px` }}

None of the three adds px to a number the way React does, so a length is written with its unit. Opacity stays a plain number.

The prop is declared where the component already declares its props:

  • Svelte: in $props() with its type, as an export let in a component written that way, or in a new <script> when there’s none.

  • Vue: a member in the type of defineProps<…>() with its default in withDefaults(…) (put around defineProps when it isn’t there) or in the destructuring; a property in defineProps({ … }); or the whole line in a component with no props yet.

  • Astro: a member in interface Props and a default in const { … } = Astro.props. Both are added when the component has neither.

Renaming and removing follow every use of the component, as in React (title="…", :title="…", and image-url for imageUrl in a Vue template). They’re refused when the component’s own code also reads the prop, in a condition or a computed value for instance: midcode says “is also read by the component’s own code”, and the change is made there.

Not written: a Vue component on the Options API or one that lists its props as defineProps([...]).

Limits

  • In the released version variables are for React function components written in JSX, in a file midcode marks (.tsx and .jsx in Next.js and Vite projects, not a plain .js file). Svelte, Vue and Astro components come with the next release. Not class components.

  • The element has to be written in the component’s own file. An element that comes from another component inside it has no plus.

  • Only plain text can become a variable. A text with code or other elements in it is refused (“Only a plain text can become a variable: this one has code or other elements in it”).

  • An attribute or a style that’s already set from code can’t be bound from the canvas: midcode says so and leaves it.

  • A style variable replaces every class that set that property on the element, including its breakpoint, variant and state classes. One value from the instance wins everywhere.

  • A padding variable is one number for all four sides. It starts from the element’s top padding.

  • A background image has no plus.

  • A variable’s name starts with a lowercase letter and has only letters and numbers (title, imageUrl). Names like children, className, style and variant are taken.

  • Changing a default from the Variables window needs the prop to be destructured with its default. Otherwise midcode asks you to change it in the code.