Escolar Documentos
Profissional Documentos
Cultura Documentos
O Tailwind CSS fornece essas classes prontas para uso. E aplicando essas classes,
podemos construir qualquer design que quisermos diretamente em nosso HTML — e
evitar o incômodo de escrever e gerenciar folhas de estilo. O Alpine.js segue um
princípio semelhante ao nos fornecer diretivas que podem ser usadas diretamente em
nosso HTML para alterar nossa interface do usuário. À medida que construímos nosso
formulário na seção subsequente, elaboraríamos mais sobre as diretivas Alpine.js e as
classes CSS do Tailwind.
Pré-requisito
Começando
# install dependencies
npm i live-server
"scripts": {
"start": "live-server"
},
Agora podemos iniciar nosso servidor usando: npm start.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1
<link
href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css"
rel="stylesheet">
<body>
<!-- body starts-->
Now that we have our application boilerplate codes, let’s start building our form in the
next section.
In our application boilerplate code above, add the following code between the body
starts and the body ends comments:
<div class="mt-6">
<div class="text-center font-semibold text-black text-2xl">
<!-- registration form starts-->
<!-- registration form ends -->
</div>
</div>
</div>
<!-- form container ends -->
</div>
</div>
In the code above, two divs that act as the application wrapper. The tailwind CSS
class min-h-screen in the outer div sets the min-height to 100vh; this constrains our
application to the height of the viewport.
The max-w-sm class in the inner div sets the max-width property to 24rem.
Also, this div holds our state — using the x-data directive.
In Alpine.js, it is necessary to declare our state in an HTML element that encapsulates all
the components we want to have access to the state. Since this div encapsulate both
our modal and form — which we would create later, it is the ideal place to declare our
state.
The x-data directive declares a new component scope using the given object. To keep
things clean, we are returning this object from the getData function — which we would
create in a moment.
Also, the x-show directive in the form container component toggles display: none; style
on the div depending if the expression: "!status && !isError" resolves to true or false.
The values of status and isError are also properties of the object returned from the
getData function.
To create the getData function add a new script tag just above the body closing tag as
seen below:
<script>
function getData() {
return {
formData: {
email: "",
password: "",
password_confirm: ""
},
status: false,
loading: false,
isError: false,
modalHeaderText: "",
modalBodyText: "",
buttonLabel: 'Submit',
}
}
</script>
<div class="py-1">
<span class="px-1 text-sm text-gray-600">Email</span>
<input placeholder="" type="text" x-model="formData.email"
class="text-md block px-3 py-2 rounded-lg w-full bg-white bord
border-gray-300 placeholder-gray-600 shadow-md focus:placeho
focus:bg-white focus:border-gray-600 focus:outline-none">
</div>
<div class="py-1">
<span class="px-1 text-sm text-gray-600">Password</span>
<input placeholder="" type="password" x-model="formData.password
class="text-md block px-3 py-2 rounded-lg w-full bg-white bord
border-gray-300 placeholder-gray-600 shadow-md focus:placehold
focus:bg-white focus:border-gray-600 focus:outline-none">
</div>
<div class="py-1">
<span class="px-1 text-sm text-gray-600">Password Confirm</span>
<input placeholder="" type="password" x-model="formData.password
class="text-md block px-3 py-2 rounded-lg w-full bg-white bord
border-gray-300 placeholder-gray-600 shadow-md focus:placehold
focus:bg-white focus:border-gray-600 focus:outline-none">
</div>
<button
class="mt-3 text-lg font-semibold bg-gray-800 w-full text-white
rounded-lg px-6 py-3 block shadow-xl hover:text-white hover:bg-b
x-text="buttonLabel" :disabled="loading">
</button>
</div>
</form>
In our code above, we use a shorthand syntax — @submit, for the x-on directive. The x-
on directive attaches an event listener to the element and when the .prevent modifier is
used — as in our form above, it calls preventDefault on the triggered event.
Also, the x-model directive adds "two-way data binding" to an element; thus it keeps
the value of the input element in sync with the component data. Since our form is within
the component scope created by the x-data directive we can use the formData object in
our input elements.
In our form button above, we disable the button using the shorthand syntax for the x-
bind directive — :disabled="loading", to disable the button when it is loading —
submitting.
The x-bind directive sets the value of an attribute to the result of an expression. This
expression has access to the component data and will update every time the data is
updated. consequently, we can dynamically add or remove classes.
Also, the x-text directive is used to dynamically add the button text.
The x-text directive works similarly to x-bind but instead of updating the values, it
updates the innerText of an HTML element.
To add reactive validation to our form, add the following codes between the validation
starts and validation ends comments:
<span
:class="{'text-green-700': formData.password.length >
'text-red-700':formData.password.length < 8 }"
class="font-medium text-sm ml-3"
x-text="formData.password.length > 7 ?
'The minimum length is reached' :
'At least 8 characters required' "></span>
</li>
<span
:class="{'text-green-700':
formData.password === formData.password_confirm,
'text-red-700':formData.password !== formData.password
class="font-medium text-sm ml-3"
x-text="formData.password === formData.password_confir
'Passwords match' : 'Passwords do not match' "></span>
</li>
</ul>
</div>
In our code above, the validate email logic validates user input dynamically using a
function called isEmail — a method of the getData function.
We make sure the validation status message, only shows when the user starts inputting
data using the x-show directive as seen below:
Also, we dynamically styled the validation message using v-bind — in our case, we used
the shorthand syntax :class as seen below:
:class="{'bg-green-200 text-green-700': isEmail(formData.email),
'bg-red-200 text-red-700': !isEmail(formData.email)
}"
To create the isEmail method, add the following code below the buttonLabel property as
seen below:
...
buttonLabel: 'Submit',
isEmail(email) {
var re = /\S+@\S+\.\S+/;
return re.test(email);
},
...
Similarly, the validate password logic, validates the password if the user input is at least
eight characters. And the password confirm, simply makes sure both passwords are the
same.
To handle submitting our form, we would add a method called submitData to the
getData function as seen below:
submitData() {
// Ensures all fields have data before submitting
if (!this.formData.email.length ||
!this.formData.password.length ||
!this.formData.password_confirm.length) {
alert("Please fill out all required field and try again!")
return;
}
this.buttonLabel = 'Submitting...'
this.loading = true;
fetch('https://reqres.in/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(this.formData)
})
.then((response) => {
if(response.status === 201) {
this.modalHeaderText = "Congratulations!!!"
this.modalBodyText = "You have been successfully regis
this.status = true;
} else{
throw new Error ("Your registration failed");
}
})
.catch((error) => {
this.modalHeaderText = "Ooops Error!"
this.modalBodyText = error.message;
this.isError = true;
})
.finally(() => {
this.loading = false;
this.buttonLabel = 'Submit'
})
}
The submitData method above first checks to ensure that all the input fields have data
before allowing submission. If any field does not contain data the alert function is called
and submitData returns.
When all the input fields contain data the submitData method continues execution and
temporarily sets buttonLabel to "submitting…" — which is displayed as the button text
and loading to true — temporarily disabling the button.
A new user is then created by making an API to a remote API — we are using REQ | RES
API in this case.
The modalHeaderText and modalBodyText are updated depending on the status of the
request — these properties would be used to display the appropriate message in our
modal.
Finally, the loading and buttonLabel are set to false and Submit respectively — returning
our button to its normal state.
We need to create a modal to display the status of our registration. To do this, add the
code below between the modal starts and modal ends comments:
In the code above, the x-show directive is used with the transition modifier to make our
modal more pleasing using CSS transitions. And the modal is shown if status or isError
evaluates to true.
The absolute class positions our modal absolutely and removes it from the document
flow.