Learn how to create a fully functional e-signature application using React for the frontend, TailwindCSS for styling, and Django REST Framework to save signatures as PNG images. Perfect for contracts, forms, or any web application needing digital signatures.
Introduction
Digital signatures are increasingly common in web apps for signing forms, agreements, or contracts online. In this tutorial, we will build an e-signature app where users can draw their signature on a canvas and save it on the server as an image file.
We’ll use:
- React for the frontend
- TailwindCSS for styling
- react-signature-canvas for drawing the signature
- Django as a backend to receive and save the signature
By the end, you’ll have a full-stack solution ready for integration into any project.
1️⃣ Frontend Setup: React + TailwindCSS
Step 1: Install dependencies
First, make sure you have a React app. If not:
npm install react-signature-canvas
(Optional but recommended)
npm install trim-canvas
Step 2: Create SignaturePad Component
Create a new file: src/pages/SignaturePad.jsx
import { useRef } from "react";
import SignatureCanvas from "react-signature-canvas";
export default function SignaturePage() {
const sigRef = useRef(null);
const clearSignature = () => {
if (!sigRef.current) return;
sigRef.current.clear();
};
const saveSignature = () => {
if (!sigRef.current || sigRef.current.isEmpty()) {
alert("Please sign first");
return;
}
const canvas = sigRef.current.getCanvas();
const dataUrl = canvas.toDataURL("image/png");
console.log("Signature Base64:", dataUrl);
// Needs to do: send to backend
};
return (
<div className="min-h-screen flex items-center justify-center">
<div className=" bg-gray-100 rounded-lg shadow-md p-6 w-full max-w-lg">
<h1 className="text-2xl font-semibold mb-4 text-center">
E-Signature
</h1>
<div className="bg-white border rounded mb-4">
<SignatureCanvas
ref={sigRef}
penColor="black"
canvasProps={{
width: 500,
height: 200,
className: "w-full h-auto"
}}
/>
</div>
<div className="flex justify-between">
<button
onClick={clearSignature}
className="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600"
>
Clear
</button>
<button
onClick={saveSignature}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
Save
</button>
</div>
</div>
</div>
);
}
2️⃣ Backend Setup: Django REST Framework
Step 1: Install Django & DRF
pip install django djangorestframework
Create a Django project and app:
django-admin startproject e-sign
cd e-sign
python manage.py startapp api
Add rest_framework and your app to INSTALLED_APPS in settings.py
INSTALLED_APPS = [
....,
'rest_framework',
'api',
]
Step 2: Create API Endpoint
Create a view to save the signature:
# api/views.py
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
import os
import base64
from django.conf import settings
class SaveSignature(APIView):
def post(self, request):
data_url = request.data.get("signature")
if not data_url:
return Response({"error": "No signature provided"}, status=status.HTTP_400_BAD_REQUEST)
try:
header, encoded = data_url.split(",", 1)
binary_data = base64.b64decode(encoded)
except Exception:
return Response({"error": "Invalid signature format"}, status=status.HTTP_400_BAD_REQUEST)
save_path = os.path.join(settings.BASE_DIR, "signatures")
os.makedirs(save_path, exist_ok=True)
# Save with unique filename
import uuid
file_name = os.path.join(save_path, f"{uuid.uuid4()}.png")
with open(file_name, "wb") as f:
f.write(binary_data)
return Response({"message": f"Signature saved at {file_name}"}, status=status.HTTP_201_CREATED)
Explanation:
- data_url.split(",", 1) separates the Base64 header from the actual data.
- base64.b64decode converts the Base64 string back to binary data.
- We save the signature in a signatures folder using a UUID filename to avoid collisions.
Step 3: Setup URLs
# api/urls.py
from django.urls import path
from .views import SaveSignature
urlpatterns = [
path("save-signature/", SaveSignature.as_view(), name="save-signature"),
]
Step 4: Include the app URLs in the project urls.py
# e-sign/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path("api/", include("api.urls")),
]
3️⃣ Connecting React to Django
Your saveSignature function in React sends a POST request with the signature in Base64 format. Django receives it, decodes it, and saves it as a PNG.
const saveSignature = async () => {
if (!sigRef.current || sigRef.current.isEmpty()) {
alert("Please sign first");
return;
}
const canvas = sigRef.current.getCanvas();
const dataUrl = canvas.toDataURL("image/png");
try {
const res = await fetch("http://127.0.0.1:8000/api/save-signature/", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ signature: dataUrl }),
});
const result = await res.json();
console.log(result);
alert(result.message);
} catch (err) {
console.error(err);
alert("Failed to save signature");
}
};
Now, running both the frontend (npm run dev) and backend (python manage.py runserver) will allow users to draw, clear, and save signatures.
✅ Conclusion
In this tutorial, you learned how to:
- Create a signature pad using react-signature-canvas
- Build a Django REST API to save signatures as PNG images
- Connect frontend and backend for a full-stack e-signature app
- This setup can be used for contracts, forms, and any web app requiring digital signatures.
Top comments (0)