SignaturePad in React: Signature appears magnified and cropped when switching to mobile simulation mode

Question:

I’m using the signature_pad library in a React JS application to capture user signatures. The signature pad works fine in desktop mode and on actual mobile devices or initial component mount in mobile inspect mode.

However, when I switch to mobile simulation mode using the browser’s developer tools (e.g., in Chrome), I encounter an issue:

  • The signature pad allows me to draw the signature correctly.

  • But when I proceed to display the signature elsewhere in the app (e.g., in a PDF or another component), the signature appears magnified and cropped, showing only the top-left quarter of the signature.


At first in desktop mode:

enter image description here

When switched to the Responsive Design Mode (aka inspect mobile mode):

enter image description here


This issue only occurs when simulating mobile devices in the browser. It does not happen in regular desktop mode or on actual startup of mobile devices or initial component mount in mobile inspect mode.

I suspect it has something to do with the device pixel ratio (DPR) or canvas scaling when switching to mobile simulation mode, but I’m not sure how to fix it.

Here is my code:

SignatureCanvas.jsx:

const SignatureCanvas = ({ canvasRef, onSignClear, turnOffSignPad }) => {
  const hideResetSignButton = turnOffSignPad;
  const disableCanvasUserSelect = turnOffSignPad ? 'none !important' : 'auto';

  return (
    <Paper
      PaperProps={{
        className: 'signature-container',
        sx: { p: 0, boxShadow: 0.25, borderRadius: 2, userSelect: disableCanvasUserSelect },
      }}
    >
      <canvas
        ref={canvasRef}
        style={{
          width: '100%',
          height: '300px',
        }}
      />
    </Paper>
  );
};

SignPaper.jsx:

function SignPaper({ foundQuote, signature, setSignature, isQuoteAccepted, closeDialog }) {
  const canvasRef = useRef(null);
  const signPadRef = useRef(null);

  const turnOffSignPad = isQuoteAccepted;

  useEffect(() => {
    const resizeCanvas = () => {
      const canvas = canvasRef.current;
      const context = canvas.getContext('2d');
      const ratio = Math.max(window.devicePixelRatio || 1, 1);

      canvas.width = canvas.offsetWidth * ratio;
      canvas.height = canvas.offsetHeight * ratio;
      context.scale(ratio, ratio);

      if (signature) {
        signPadRef.current.fromDataURL(signature);
      } else {
        clearSign();
        closeDialog();
      }
    };

    if (!signPadRef.current) {
      signPadRef.current = new SignaturePad(canvasRef.current);
    }

    resizeCanvas();

    if (turnOffSignPad) {
      signPadRef.current.off();
    }

    window.addEventListener('resize', resizeCanvas);
    signPadRef.current.addEventListener('endStroke', saveSignature);

    return () => {
      window.removeEventListener('resize', resizeCanvas);
      signPadRef.current.removeEventListener('endStroke', saveSignature);
    };
  }, []);

  const clearSign = () => {
    if (signPadRef.current && signature !== null) {
      signPadRef.current.clear();
      setSignature(null);
    }
  };

  const saveSignature = () => {
    if (signPadRef.current && !signPadRef.current.isEmpty()) {
      const signData = signPadRef.current.toDataURL('image/svg+xml');
      setSignature(signData);
    }
  };

  return (
    <Paper>
      <SignatureCanvas
        canvasRef={canvasRef}
        onSignClear={clearSign}
        turnOffSignPad={turnOffSignPad}
      />
    </Paper>
  );
}


Questions:

  1. Why does the signature appear magnified and cropped when switching to mobile simulation mode in the browser’s developer tools?

  2. How can I fix this issue so that the signature displays correctly in all modes, including mobile simulation mode?