IsraelVotes.ca

Role: Founder
WebflowJavaScript

What is IsraelVotes.ca?

In late March of 2025, the Canadian Prime Minister dissolved parliament, setting the stage for a historic election. With the nation at a crossroads, and the welfare of Canada's Jewish community of nearly half a million at stake, I created IsraelVotes.ca to streamline voter registration for Canadian expats living in Israel.

There was no time to waste so I built the site rapidly, going from idea to launch in just 72 hours. I chose Webflow for this project, as it's the tool I have the most experience in, and can handle every stage from design to build to deployment.

IsraelVotes.ca landing page
IsraelVotes.ca landing page

The reaction from the community was overwhelmingly positive, and the project received media coverage both in Israel and Canada.

The Multi-Step Form

The process for voter registration on the Canadian Government's website involved one long and complex form. I decided a multi-step approach that adapted to the user's answers would be the best way to streamline the process.

To implement this, I built the entire website as a single-page application (SPA) in Webflow and used Formly, a streamlined multi-step form library built for Webflow. Formly was a great choice because it managed to combine a simple approach of defining form step divs, with a powerful logic engine that allowed for conditional rules using nothing more than HTML attributes.

Design of the multi-step form in Webflow
Design of the multi-step form in Webflow

Although the election has passed, I have enabled the form on the staging site so you can try it out. Some validations (e.g. file upload) currently appear to error since the backend is no longer deployed, but the flow will still work for your testing. The form is inert and won't submit any data to Elections Canada.

The multi-step form in practice

User Experience Considerations

The primary concern throughout the creation of IsraelVotes was optimizing for user experience everywhere. The assumption was that any friction on UX would result in less Canadians getting registered and voting in the election, defeating the purpose of the project. As a result, many considerations were made to ensure the best possible user experience.

Perfect Phone Number Inputs

Elections Canada required the voter's phone number for their records, and WhatsApp was my primary method of communication with registrants. Since I am dealing with a multinational userbase between Canada and Israel, I had to ensure that the phone number input was optimized for this use case.

Perfect Phone Number Input Field

I implemented a Memberstack script called Perfect Phone Number Inputs, which provides an effortless interface for users to input their phone numbers with country code selection and realtime client side validation. The script also allowed me to set preferred country codes (Israel +972 and Canada +1) to appear at the top of the dropdown menu using a custom attribute.

Date of Birth Entry and Validation

For users to input their date of birth to the form, I implemented the date picker library flatpickr. Flatpickr integrated seamlessly into Webflow with just a css and js import.

Canadian law allows citizens who are 18 years or older on the day of the election to register and vote. This made the youngest eligible voter's birthday April 28, 2007. Flatpickr allowed me to set the maximum allowed date with a simple function, further streamlining the user experience.

Flatpickr implementation with maxDate
Webflow.push(function () {
	document.getElementsByClassName('date').flatpickr({
    maxDate: "2007-04-28" // 18 on election day
  });
});

Google Maps Address Autocomplete

Inputting a physical address is a consistent annoyance for users of any website, yet is necessary for parliamentary riding verification (Canadian Address) and ballot delivery (Israeli Address).

To reduce user friction, I implemented Google Maps Address Autocomplete, which provides an efficient and accurate address autocomplete to the form.

Google Maps Address Autocomplete
function initAutocomplete() {
  autocomplete = new google.maps.places.Autocomplete(
    document.querySelector('input[ms-code-input="address"]'),
    {
      fields: ['address_components'],
      types: ['address']
    }
  );

A bug presented itself when a user would select an autocomplete suggestion. The form would not allow the user to proceed to the next step until they manually updated the DOM. To fix this behavior, I wrote a listener function that used client-side events to simulate a user typing an input after the input field was hydrated by the Google Maps API.

autocomplete.addListener('place_changed', function() {
  const place = autocomplete.getPlace();

  if (place) {
    const fields = {
      'address': extractAddress(place),
      'city': extractCity(place),
      'region': extractRegion(place),
      'postal-code': extractPostalCode(place)
    };

    Object.entries(fields).forEach(([msCode, value]) => {
      const input = document.querySelector(`input[ms-code-input="${msCode}"]`);
      if (input) {
        input.value = value;

        // Simulate real typing by triggering input/change with slight delay
        setTimeout(() => {
          input.dispatchEvent(new Event('focus', { bubbles: true }));
          input.dispatchEvent(new Event('input', { bubbles: true }));
          input.dispatchEvent(new Event('change', { bubbles: true }));
          input.dispatchEvent(new Event('blur', { bubbles: true }));
        }, 50);
      }
    });
  }
});

Form Review and Confirmation Final Step

When the user completed the form, a final screen was presented with the user's complete input data displayed, allowing for one final review before submitting their voter declaration and completing their registration.

To facilitate form review data hydration, I wrote a function to retrieve the relevant data from the DOM and populate the form review step.

Final form review step
document.addEventListener('DOMContentLoaded', function() {
  const fieldsToVerify = [
    'register-given-name',
    'register-middle-name',
    'register-family-name',
    'register-phone',
    'register-email',
    'gender',
    'date'
  ];

  verifyCanadaAddress {
    if (locationInput && locationInput.value.trim() !== '') {
      verifyCanadaAddress.textContent = 'Will Follow Up';
    } else {
      const canadaAddressFields = [
        'canada-address-line',
        'canada-address-line-2',
        'canada-address-city',
        'canada-address-province',
        'canada-address-post-code'
      ];

  verifyIsraelAddress {
    const programOrganizer = document.getElementById('program-organizer')?.value.trim();
    const embassyEmail = document.getElementById('embassy-email')?.value.trim();
    const israelAddressFields = [
      'israel-address-line',
      'israel-address-line-2',
      'israel-address-city',
      'israel-address-post-code'
    ];
  }
}

Hidden Inputs

There are two pieces of data submitted with the form that are set automatically and passed via hidden inputs.

  • uuid: A unique identifier for the submission, to ensure that each registration is tracked for any necessary follow-up communication.
const uuidInput = document.getElementById('uuid');

uuidInput.value = crypto.randomUUID
  • language: The user's language as set by Webflow's built in internationalization. This allows us to know which language to use for any follow-up communication with the user.
const languageInput = document.getElementById('language');
const path = window.location.pathname;

let lang = 'e'; // default english

if (path.startsWith('/fr-ca')) lang = 'f'; // french
else if (path.startsWith('/he')) lang = 'h'; // hebrew

languageInput.value = lang;

Dynamic Hero Call-to-Action

To create a sense of urgency, I implemented a dynamic call to action in the hero section that automatically updated a countdown of days until the election. On the day of the election, the message displayed Canada Votes Today! and after the election, the message displays The election has passed.

This message is translated and localized based on the user's language preference.

Dynamic Hero Call-to-Action (date set to April 1, 2025)
Date set to April 1, 2025
document.addEventListener('DOMContentLoaded', function() {
  const targetDate = new Date('2025-04-28T00:00:00'); // Election date
  const countdownElement = document.getElementById('vote-countdown');

  const today = new Date();
  today.setHours(0,0,0,0);
  const diffTime = targetDate - today;
  const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));

  // Detect language from URL path
  const path = window.location.pathname;
  let lang = 'en'; // default language

  if (path.startsWith('/fr-ca')) lang = 'fr';
  else if (path.startsWith('/he')) lang = 'he';

  const messages = {
    en: {
      daysLeft: days => `Canada Votes in ${days} Day${days > 1 ? 's' : ''}`,
      today: "Canada Votes Today!",
      passed: "The election has passed."
    },
    fr: {
      daysLeft: days => `Le Canada vote dans ${days} jour${days > 1 ? 's' : ''}`,
      today: "Le Canada vote aujourd’hui!",
      passed: "L’élection est terminée."
    },
    he: {
      daysLeft: days => `קנדה מצביעה בעוד ${days} יום${days > 1 ? 'ים' : ''}`,
      today: "קנדה מצביעה היום",
      passed: "הבחירות כבר התקיימו"
    }
  };

  let message;

  if (diffDays > 0) {
    message = messages[lang].daysLeft(diffDays);
  } else if (diffDays === 0) {
    message = messages[lang].today;
  } else {
    message = messages[lang].passed;
  }

  countdownElement.textContent = message;
});

Internationalization

Internationalization was managed using Webflow's native localization feature, and manually selectable via a dropdown menu in the navbar. This ensured that voters were able to register regardless of whether they understood English, French, or Hebrew best.

While this feature was used while the project was active, it is not currently accessible on the staging website since it is an expensive add-on.

Language selection dropdown: English, French, Hebrew

Final Thoughts

By election day we had mobilized over a thousand voters. The biggest accomplishment for me was not in any technical achievement, but in seeing the real impact the project had on the Canadian Jewish and expat communities. Having my project covered by the Times of Israel and being interviewed on the Canadian Jewish News Daily Podcast is a career highlight of mine.

IsraelVotes.ca is one of my all-time favorite projects. I learned how to build faster than I ever have before, and extend the capabilities of Webflow in ways I didn't even know was possible.