Utilizing a component-based frontend makes growing internet apps simpler and extra manageable. Builders can construct a good app in a matter of hours with frameworks like Vue.js, React, and Angular.
Moreover, builders typically use UI libraries with pre-made parts, equivalent to Vuetify, to hurry up and facilitate the event course of much more.
On this tutorial, we’ll discover top-of-the-line Vue-based UI element libraries known as PrimeVue and learn how to use it with Vue 3 to create a pattern app. We are going to cowl:
What’s PrimeVue?
PrimeVue is a member of a household of open supply UI element libraries supplied by PrimeTek.
Moreover the PrimeVue element library, PrimeTek additionally gives variations for Java (PrimeFaces), Angular (PrimeNG), and React (PrimeReact). That is nice as a result of you may change from one framework to a different and nonetheless have nearly similar parts to work with.
PrimeVue gives a wealthy set of greater than 90 responsive UI parts — sufficient to cowl a broad vary of use instances. It additionally provides some distinctive parts like Terminal, a text-based UI, and Dock, a navigation element.
One other advantage of PrimeVue is that it’s design-agnostic, so you aren’t constrained to Materials or Bootstrap-like kinds. There are tons of various themes you may select from on your app, or you may construct your individual.
PrimeVue provides nice documentation for every element with devoted examples for each Choices API and Composition API. Documentation is brief, clear, and straightforward to each comply with and perceive.
Exploring the PrimeVue ecosystem
PrimeVue comes with some nice additions to the principle library, together with PrimeIcons, PrimeFlex, Theme Designer, Templates, and Blocks. Let’s go over every of those in additional element.
PrimeIcons
PrimeIcons is a set of over 200 generally used icons you need to use with all Prime UI libraries. Due to PrimeIcons, you don’t want so as to add third-party packages like Font Superior to entry and show icons in your utility.
PrimeFlex
PrimeFlex is a CSS utility library, just like TailwindCSS. It’s good match for PrimeVue.
Usually, most UI libraries (together with PrimeVue) have roughly opinionated kinds for his or her parts, which are sometimes exhausting to tweak. That is the place a library like PrimeFlex may also help.
Utility lessons provide the skill to regulate or change element’s look rapidly and simply. As a bonus, PrimeFlex seamlessly integrates with PrimeVue and different family members.
Theme Designer
Theme Designer is a web-based instrument that offers you full management over how parts will look in your utility. Should you don’t wish to use PrimeFlex, then the PrimeVue Visible Theme Designer may also help you to create the feel and appear you’re striving for.
This handy instrument requires a license to make use of all its options.
Templates
You’ll be able to select from a assortment of Templates on your Vue app. Whereas these templates are handy, a lot of the PrimeVue templates are for buy solely, beginning at round $19.
PrimeBlocks
PrimeBlocks for PrimeVue is a set of over 350 ready-to-use UI blocks, equivalent to layouts, navigations, varieties, pages, and so forth. Although there are some free blocks, you will want a license to entry the complete assortment.
Extra nice articles from LogRocket:
Be aware that the final three assets — Theme Designer, Templates, and PrimeBlocks — are principally paid. Nonetheless, there’s a lot you may obtain by PrimeVue with no need to pay for added options.
Now, when we’ve got an excellent understanding what PrimeVue is and what goodies it gives, let’s discover learn how to use this library’s parts.
Getting began with PrimeVue and Vue 3
To get began, we’ll use Vite to scaffold a brand new Vue venture. Run the next in your terminal:
npm create [email protected]
After following the prompts to finish scaffolding, navigate to the venture and set up the dependencies:
cd your-project npm set up
Now let’s add PrimeVue, PrimeIcons, and PrimeFlex to the venture by working the next instructions:
npm set up [email protected]^3.15.0 npm set up primeicons npm set up primeflex
Subsequent, let’s take a look at an instance of importing a PrimeVue element. Open principal.js
and exchange its content material with the next:
import {createApp} from 'vue' import App from './App.vue' import PrimeVue from 'primevue/config' // import PrimeVue // import CSS assets import 'primevue/assets/primevue.min.css' // core import 'primevue/assets/themes/saga-blue/theme.css' // theme import 'primeicons/primeicons.css' // icons import '/node_modules/primeflex/primeflex.css' // PrimeFlex import Button from 'primevue/button' // import Button element const app = createApp(App) // create new Vue app app.use(PrimeVue) // register PrimeVue app.element('Button', Button) // register Button element app.mount('#app') // mount the app
Now you need to use the PrimeVue Button
element in Vue templates like this:
<Button label="Submit" />
That is how straightforward is to make use of PrimeVue parts. Merely import and register them, and they’re prepared to be used.
Be aware that to get code completion and snippets assist for PrimeFlex utility lessons, you may set up the official extension for VS Code.
Constructing a easy note-taking app with PrimeVue and Vue 3
On this part, we’ll discover PrimeVue parts additional by constructing a easy note-taking app.
Here’s a preview of what we’re going to construct:
Customers will be capable of create, edit, and delete notes. Every be aware will comprise a title, some content material, and a tag or tags.
We can even add performance for looking out notes utilizing a search bar and filtering them by tag, plus the flexibility so as to add notes to a “Favorites” assortment, which may be explored independently.
Importing and registering PrimeVue parts
For this app, we’ll use a bunch of PrimeVue parts. To import and register these parts, exchange the content material of principal.js
file with the next:
import { createApp } from 'vue' import App from './App.vue' import PrimeVue from 'primevue/config' import 'primevue/assets/primevue.min.css' import 'primevue/assets/themes/lara-dark-blue/theme.css' import 'primeicons/primeicons.css' import '/node_modules/primeflex/primeflex.css' import Panel from 'primevue/panel' import Toolbar from 'primevue/toolbar' import Button from 'primevue/button' import Dropdown from 'primevue/dropdown' import AutoComplete from 'primevue/autocomplete' import Card from 'primevue/card' import Tag from 'primevue/tag' import Dialog from 'primevue/dialog' import Inplace from 'primevue/inplace' import InputText from 'primevue/inputtext' import Editor from 'primevue/editor' import Chips from 'primevue/chips' import Tooltip from 'primevue/tooltip' const app = createApp(App) app.use(PrimeVue) app.element('Panel', Panel) app.element('Toolbar', Toolbar) app.element('Button', Button) app.element('Dropdown', Dropdown) app.element('AutoComplete', AutoComplete) app.element('Card', Card) app.element('Tag', Tag) app.element('Dialog', Dialog) app.element('Inplace', Inplace) app.element('InputText', InputText) app.element('Editor', Editor) app.element('Chips', Chips) app.directive('tooltip', Tooltip) app.mount('#app')
Within the code above, we added all the mandatory parts, plus the Tooltip
directive.
The following step is to rename the HelloWord.vue
file inside parts
listing to NotesWriter.vue
. Then, edit the App.vue
file to replicate the modified filename:
<script setup> // This starter template is utilizing Vue 3 <script setup> SFCs // Try https://vuejs.org/api/sfc-script-setup.html#script-setup import NotesWriter from './parts/NotesWriter.vue' </script> <template> <NotesWriter /> </template>
Now, we’re prepared to begin the enjoyable half.
Organising our app
Open the NotesWriter.vue
file and exchange its content material with the next:
><script setup> import { ref, reactive, computed, onMounted, watchEffect } from 'vue' // Native storage setup const STORAGE_KEY = 'notes' const notes = ref(JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]')) watchEffect(() => { localStorage.setItem(STORAGE_KEY, JSON.stringify(notes.worth)) }) // Get present state const currentNotes = ref() const currentNote = reactive({ id: null, title: 'Give me a reputation', content material: '', tags: [], fav: false }) // Get notes onMounted(() => { allNotes() }) operate allNotes() { currentNotes.worth = notes.worth } operate favNotes() { currentNotes.worth = notes.worth.filter((be aware) => be aware.fav === true) } // Dialog logic const displayDialog = ref(false) operate openDialog() { displayDialog.worth = true } operate closeDialog() { displayDialog.worth = false } </script>
To start with of the code above, we imported all of the Vue features and utilities we’ll want.
Then, we arrange native storage for the notes. Notes can be fetched from the native storage for the consumer to view or edit. The storage will then be up to date on adjustments through the use of the watchEffect
operate.
The watchEffect
operate runs each time any of its dependencies are modified. In our case, the dependency is the notes
array.
Subsequent, we outlined two variables: currentNotes
can be used to show the present filtered notes assortment, and currentNote
can be used after we create or edit a single be aware.
Within the subsequent part, we used onMounted
hook to load notes on element mounting.
With the allNotes
operate, we are able to assign notes
to currentNotes
so we are able to render all created notes. With the favNotes
operate, we are able to filter the notes
array to get all notes with the fav
key set to true
, then assign the end result to currentNotes
so we are able to render them within the “Favorites” assortment.
The final a part of the code units the logic for the Dialog
element, which we’ll use to create and edit notes.
Now, let’s add the element templates.
Including PrimeVue element templates
Put the next code after the script tag:
<template> <div> <Panel header="Notes Author"> <Toolbar class="mb-6"> <template #begin> <Button class="mr-3" label="New" icon="pi pi-plus" @click on="addNote" /> <span class="p-buttonset"> <Button class="p-button-success" label="All notes" icon="pi pi-list" @click on="allNotes" /> <Button class="p-button-danger" label="Favorites" icon="pi pi-heart" @click on="favNotes" /> </span> </template> <template #finish> <!-- Add filter and search performance right here afterward --> </template> </Toolbar> <div class="flex flex-wrap justify-content-around gap-3"> <div class="text-xl" v-if="!notes.size">No notes have been created but. Hit the <b>New</b> button to create one.</div> <Card class="w-3 bg-bluegray-900 shadow-4" v-for="(be aware, index) in currentNotes" :key="index"> <template #title> {{ be aware.title }} </template> <template #subtitle> <Tag class="mr-2" :worth="tag" v-for="tag in be aware.tags"></Tag> </template> <template #content material> <div class="overflow-hidden max-h-5rem" v-html="be aware.content material"></div> </template> <template #footer> <Button class="p-button-rounded p-button-text" v-tooltip.backside="'Edit'" icon="pi pi-pencil" @click on="editNote(be aware)" /> <Button class="p-button-rounded p-button-text p-button-danger" v-tooltip.backside="'Add to Favorites'" :icon="be aware.fav ? 'pi pi-heart-fill' : 'pi pi-heart'" @click on="be aware.fav = !be aware.fav" /> <Button class="p-button-rounded p-button-text text-red-500" v-tooltip.backside="'Delete'" icon="pi pi-trash" @click on="removeNote(be aware)" /> </template> </Card> </div> </Panel> <!-- Add Dialog element right here afterward --> </div> </template>
Within the code above, we wrapped our app right into a Panel
element and set the app’s title through the use of the header
property. Then, we used a Toolbar
element so as to add the mandatory buttons.
We added some backside margin to the toolbar through the use of the PrimeFlex utility class (mb-6
). It will add some area between the toolbar and notes.
The Toolbar
element has two slots, begin
and finish
, which serve to place toolbar components on the left and proper sides, respectively. We used the begin
slot right here so as to add a single button for creating new notes in addition to a button set for “All notes” and “Favorites” buttons.
To make use of PrimeIcons, we have to add the icon
property for a specific element and set its worth following this sample: pi pi-[icon-name]
. On this case, we set the primary button element’s icon like this: pi pi-plus
.
For every button, we assigned the corresponding operate to the click on
occasion handler.
We’ll create the addNote
button within the subsequent part. We’ll additionally use the finish
slot of the Toolbar
element later so as to add inputs for looking out and filtering notes.
After caring for the buttons within the code above, we used a wrapping div
for notes, which makes use of flex utility lessons to type the notes correctly. Then, we’ve got one other div
that reveals a message if no notes have been created but (i.e., if the notes
array is empty).
Subsequent, we used a Card
element to symbolize a single be aware. We are able to iterate on currentNotes
and use the cardboard’s slots (title
, subtitle
, content material
, footer
) to populate the be aware’s knowledge, utilizing a Tag
element to render be aware’s tags and a v-html
directive to show the be aware’s content material as HTML.
Lastly, we used the Tooltip
directive so as to add a touch to every button. For the “Add to Favorites” button, we used a ternary operator to test be aware’s fav
worth and set the suitable icon accordingly. On every click on, the be aware’s fav
worth is modified from true
to false
or vice versa.
I’ve used a number of utility lessons within the above template to make the design a bit extra nice. PrimeVue additionally use its personal lessons, which you’ll acknowledge by the p
prefix — for instance, as in p-buttonset
.
Let’s see what we’ve carried out to date. Run the venture with the next command:
npm run dev
Once you go to the app’s deal with (http://127.0.0.1:5173/) it is best to see the next in your browser window:
Fairly cool!
Creating features for including, modifying, saving, and eradicating notes
Add the next contained in the script
tag:
// Notes actions const isNewNote = ref(false) operate addNote() { isNewNote.worth = true currentNote.id = Date.now() currentNote.title="Give me a reputation" currentNote.content material="" currentNote.tags = [] currentNote.fav = false openDialog() } operate editNote(be aware) { currentNote.id = be aware.id currentNote.title = be aware.title currentNote.content material = be aware.content material currentNote.tags = be aware.tags currentNote.fav = be aware.fav openDialog() }
Right here, we first set an isNewNote
variable, which can be used to outline whether or not we’re creating a brand new be aware or modifying an present one.
Subsequent, within the addNote
operate, we arrange currentNote
with preliminary values after which opened the dialog. We additionally set isNewNote
to true
to point that we wish to create a brand new be aware.
Within the editNote
operate, we assigned the information from edited be aware to the currentNote
in order that after we open the dialog, it should present the edited be aware’s knowledge.
Let’s add the remainder of the actions:
operate saveNote() { if (isNewNote.worth === false) { let be aware = notes.worth.discover((be aware) => be aware.id === currentNote.id) let editedNote = Object.assign({}, currentNote) notes.worth.splice(notes.worth.indexOf(be aware), 1, editedNote) currentNotes.worth[currentNotes.value.indexOf(note)] = editedNote } else { let newNote = Object.assign({}, currentNote) notes.worth.push(newNote) isNewNote.worth = false } closeDialog() } operate removeNote(be aware) { if (currentNotes.worth === notes.worth) { notes.worth.splice(notes.worth.indexOf(be aware), 1) } else { notes.worth.splice(notes.worth.indexOf(be aware), 1) currentNotes.worth.splice(currentNotes.worth.indexOf(be aware), 1) } }
The saveNote
operate above first checks whether or not we saved the edited be aware — in different phrases, if the worth of isNewNote
is false
. In that case, we get the be aware through the use of the currentNote.id
. Then we clone the currentNote
through the use of Object.assign()
.
We do that to interrupt the hyperlink between the currentNote
and the edited be aware. They’re linked as a result of in JavaScript, objects are copied by reference; after we edit the supply object, the copied object is up to date too, and vice versa.
Then we up to date our notes
and currentNotes
arrays. We have to replace each for the adjustments to be seen after we see all notes in addition to filtered notes.
If we save a brand new be aware, we push it to the notes
array and set isNewNote
again to false
.
Within the removeNote
operate, we test if currentNotes
and notes
are equal. In that case, we have to replace solely notes
. If not, we have to replace each notes
and currentNotes
for a similar motive talked about above relating to the saveNote
operate.
Utilizing PrimeVue parts for our notes modifying interface
Within the subsequent part, we’ll use the Editor
element, which has the Quill textual content editor as a dependency. We have to set up it first, so cease the app and run the next:
npm set up quill
Now run the app once more with the npm run dev
command.
Nice! Now let’s add the code for the dialog. Add the next after the Panel
element:
<Dialog header="Be aware" v-model:seen="displayDialog" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :type="{width: '50vw'}" :maximizable="true" :modal="true"> <Inplace :closable="true"> <template #show> <span class="text-xl">{{ currentNote.title }}</span> </template> <template #content material> <InputText v-model="currentNote.title" /> </template> </Inplace> <Editor class="my-4" v-model="currentNote.content material" editorStyle="top: 320px"> <template #toolbar> <span class="ql-formats"> <button class="ql-bold" v-tooltip.backside="'Daring'"></button> <button class="ql-italic" v-tooltip.backside="'Italic'"></button> <button class="ql-underline" v-tooltip.backside="'Underline'"></button> </span> </template> </Editor> <span class="p-float-label"> <Chips v-model="currentNote.tags" separator="," /> <label for="chips">Add tags...</label> </span> <template #footer> <Button class="p-button-text" label="Cancel" icon="pi pi-times" @click on="closeDialog" /> <Button label="Save" icon="pi pi-check" @click on="saveNote" /> </template> </Dialog>
Right here, we used the Dialog
element so as to add an modifying interface for the notes. It should open a modal window wherein we are able to edit be aware’s title, content material, and tags. We’re doing a number of issues with this element:
- Utilizing the
displayDialog
variable to open or shut the dialog - Making the dialog responsive by including some breakpoints
- Setting the
modal
andmaximizable
properties totrue
We additionally used the Inplace
element for title modifying together with the InputText
element. This permits the consumer to edit the title by merely clicking on it, then clicking the shut button when completed.
Then, we used an Editor
element for the be aware’s content material. We’ve added solely three formatting buttons, which is totally sufficient for easy notes.
Subsequent, we created a float-label
enter the place we are able to add tags to our notes through the use of the Chips
element. So as to add tags, we have to separate them with commas.
And lastly, we added two buttons within the footer to Cancel
be aware creation or Save
a created be aware.
Right here is how the Dialog
element seems after we create a brand new be aware:
And after we edit the be aware:
Right here is how the created be aware seems:
Now we are able to create as many notes as we want utilizing our app. Nonetheless, as we add notes, it should change into tougher to seek out those you want. That’s why the final step in constructing the app is so as to add looking out and filtering capabilities.
Including looking out and filtering capabilities
Add this code contained in the script tag:
// Filter notes logic const selectedTag = ref() const tags = computed(() => { let allTags = [] notes.worth.map((be aware) => allTags = allTags.concat(be aware.tags)) let uniqueTags = [...new Set(allTags)] return uniqueTags }) operate filterNotes() { currentNotes.worth = notes.worth.filter((be aware) => be aware.tags.consists of(selectedTag.worth)) }
Right here, we created a computed fixed known as tags
that will get all tags from all notes, then removes the repeated tags by creating a brand new Set()
, which may comprise solely distinctive objects.
Then, we outlined a filterNotes
operate, which permits us to get all notes with a particular tag.
Now add the next contained in the #finish
template within the toolbar element:
<template #finish> <div class="flex"> <Dropdown class="mr-3" v-model="selectedTag" :choices="tags" placeholder="Filter by tag" @change="filterNotes" @blur="selectedTag = ''" /> </div> </template>
Right here, we used a Dropdown
element to permit us to pick out the tag we wish. On @blur
, we set the selectedTag
to an empty string so the enter can be cleared.
Subsequent, add the next contained in the script
tag:
// Search notes logic const foundNotes = ref() operate searchNote(occasion) { setTimeout(() => { if (occasion.question.trim().size) { foundNotes.worth = notes.worth.filter((be aware) => { return be aware.title.toLowerCase().startsWith(occasion.question.toLowerCase()) }) } }, 250) } const selectedNote = ref() operate searchNotes() { currentNotes.worth = [notes.value.find((note)=>note.title === selectedNote.value.title)] }
Within the code above, in our searchNote
operate, we first added a setTimeout
operate so as to add a brief delay earlier than the element shows the search outcomes.
We are able to use the searchNote
operate to test if the enter question is just not empty through the use of the occasion
parameter. If the enter question is just not empty, we filter the notes by the question.
We then outlined a searchNotes
operate, which permits us to discover a be aware by its title and put it in an array that we assign to currentNotes
.
The very last thing we have to do is so as to add the AutoComplete
element within the template, which we are going to add after the Dropdown
element:
<div class="flex"> <Dropdown class="mr-3" v-model="selectedTag" :choices="tags" placeholder="Filter by tag" @change="filterNotes" @blur="selectedTag = ''" /> <div class="p-inputgroup"> <span class="p-inputgroup-addon"> <i class="pi pi-search"></i> </span> <AutoComplete placeholder="Search notes..." subject="title" v-model="selectedNote" :options="foundNotes" @full="searchNote($occasion)" @item-select="searchNotes" @blur="selectedNote=""" /> </div> </div>
Within the code above, we used an AutoComplete
element with an InputGroup
element, which provides an icon earlier than the enter.
Right here is how the app seems like with Dropdown
and AutoComplete
parts added:
Testing and previewing app options
Now that we’re completed with the code for our venture, we are able to check and preview the completely different options we added. The picture under reveals the outcomes of filtering our notes by the Vue
tag:
After we search our notes, we should always see some options pop up beneath the “Search notes…” placeholder:
After including an enter question, the app ought to show the discovered be aware, like so:
After clicking the “Favorites” button, the app ought to show the “Favorites” assortment, like so:
Conclusion
As we noticed, PrimeVue is a component-rich UI library that provides an entire UI constructing answer, distinctive parts, straightforward theming, and nice documentation.
We’ve gone by constructing a easy however practical note-taking app that makes use of a number of PrimeVue parts. We realized learn how to mix them collectively to create the options we wish for our app.
Armed with this data and PrimeVue intensive documentation, you can begin constructing your individual much more advanced apps. Glad coding!
LogRocket proactively surfaces and diagnoses an important points in your Vue apps
Hundreds of engineering and product groups use LogRocket to cut back the time it takes to grasp the foundation reason behind technical and value points of their Vue apps. With LogRocket, you will spend much less time on back-and-forth conversations with prospects and take away the infinite troubleshooting course of. LogRocket means that you can spend extra time constructing new issues and fewer time fixing bugs.
Proactively repair your Vue apps — attempt LogRocket at present.