Polotno
Side panel

Customizing Resize Panel

Build your own Sizes panel with presets and unit-aware inputs

How to set your own default page sizes?

You can make your own panel from scratch and define new Sizes section. For example:

import React, { useState, useEffect } from 'react';
import { observer } from 'mobx-react-lite';
import {
  Button,
  NumericInput,
  Select,
  SelectTrigger,
  SelectContent,
  SelectItem,
  SelectValue,
} from 'polotno/primitives';
import { pxToUnitRounded, unitToPx } from 'polotno/utils/unit';

const MIN_PX = 10;

const PRESETS = [
  { label: 'IG Post', w: 1080, h: 1080, unit: 'px' },
  { label: 'IG Story', w: 1080, h: 1920, unit: 'px' },
  { label: 'Full HD', w: 1920, h: 1080, unit: 'px' },
  { label: 'A4', w: 21, h: 29.7, unit: 'cm' },
  { label: 'Letter', w: 8.5, h: 11, unit: 'in' },
];

export const ResizePanel = observer(({ store }) => {
  const [w, setW] = useState(0);
  const [h, setH] = useState(0);

  useEffect(() => {
    setW(
      pxToUnitRounded({ px: store.width, unit: store.unit, dpi: store.dpi })
    );
    setH(
      pxToUnitRounded({ px: store.height, unit: store.unit, dpi: store.dpi })
    );
  }, [store.width, store.height, store.unit, store.dpi]);

  const applyResize = (unitW = w, unitH = h) => {
    const widthPx = unitToPx({
      unitVal: unitW,
      unit: store.unit,
      dpi: store.dpi,
    });
    const heightPx = unitToPx({
      unitVal: unitH,
      unit: store.unit,
      dpi: store.dpi,
    });
    if (widthPx >= MIN_PX && heightPx >= MIN_PX)
      store.setSize(widthPx, heightPx, true);
  };

  const Row = ({ children }) => (
    <div
      style={{
        display: 'flex',
        alignItems: 'center',
        gap: 8,
        marginBottom: 10,
      }}
    >
      {children}
    </div>
  );

  return (
    <div style={{ padding: 16, overflowY: 'auto', maxHeight: '100%' }}>
      <Row>
        <div style={{ width: 60 }}>Width</div>
        <NumericInput value={w} onValueChange={setW} min={1} />
      </Row>
      <Row>
        <div style={{ width: 60 }}>Height</div>
        <NumericInput value={h} onValueChange={setH} min={1} />
      </Row>
      <Row>
        <div style={{ width: 60 }}>Units</div>
        <Select
          value={store.unit}
          onValueChange={(unit) => store.setUnit({ unit, dpi: store.dpi })}
        >
          <SelectTrigger style={{ width: '100%' }}>
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            {['px', 'cm', 'in'].map((u) => (
              <SelectItem key={u} value={u}>
                {u}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </Row>
      <Button
        onClick={() => applyResize()}
        style={{ width: '100%', marginBottom: 16 }}
      >
        Resize
      </Button>

      {/* preset buttons, one per row */}
      {PRESETS.map(({ label, w: pw, h: ph, unit }) => (
        <Button
          key={label}
          style={{ width: '100%', height: 60, marginBottom: 8 }}
          onClick={() => {
            store.setUnit({ unit, dpi: store.dpi });
            applyResize(pw, ph);
          }}
        >
          {label}
          <span style={{ fontSize: '0.75em', marginLeft: 6, opacity: 0.7 }}>
            {pw}×{ph} {unit}
          </span>
        </Button>
      ))}
    </div>
  );
});

Live demo

On this page