client-side validation