Modern HTTP-Requests for login/register system
Declaring a class makes sense if it can be reused, but less so if the logic and element ids are hardcoded to just one case, it only adds the unnecessary this. to variables.
It's unclear why the click listener is handled outside of the form class as it's logically and conceptually a part of the form.
JS naming convention is camelCase, not snake_case.
Consider URLSearchParams API so the HTTP headers are set automatically and values are properly escaped.
Consider making the login routes more declarative e.g. routes in the code below.
If your goal was to use a class as a namespace then it might be better to switch to modules. For example using the built-in ES modules the inner contents of the function will be the entire contents of the module.


function handleLogin() {
  const request = new XMLHttpRequest();
  const loader = document.getElementById('loader');
  const btn = document.getElementById('right');
  let step = 0;
  const routes = [{
    path: 'one',
    field: 'username',
    onload() {
      step++;
      getDataElement().focus();
    },
    onerror(e) { /* show error */ },
  }, {
    path: 'two',
    field: 'password',
    onload() { /* show home page */ },
    onerror(e) { /* show error */ },
  }];

  btn.addEventListener('click', () =&gt; {
    loader.style.opacity = 1;
    const {path, field} = routes[step];
    request.open('post', `/login/step_${path}`);
    request.send(new URLSearchParams({[field]: getDataElement().value}));
  });

  request.addEventListener('loadend', e =&gt; {
    loader.style.opacity = 0;
    routes[step][request.response === 'true' ? 'onload' : 'onerror'](e);
  });

  function getDataElement() {
    return document.getElementById(routes[step].field);
  }
}