Alexander Godwin I'm a software developer and writer that likes to write code and build things. Currently I'm fascinated by distributed systems and cloud computing.

Using vue-clamp to truncate text in Vue apps

8 min read 2514

Using Vue-clamp To Truncate Text In Vue Apps

In a Vue.js application, truncating text can help display large amounts of text in a limited space, such as in a list or a card. Truncating text can help improve the readability and layout of the content by ensuring that it doesn’t take up too much space or become overwhelming for the user.

To truncate text in a Vue.js app, you can use the vue-clamp library. This library provides a simple and lightweight component that adds a “Read more” link to reveal the full text in a designated area. This allows users to choose whether they want to read the full text or just the truncated version.

In this article, we’ll look at how to use the vue-clamp library to truncate text in Vue.js applications.

Jump ahead:

Introduction to vue-clamp

As stated in the introduction, vue-clamp is an npm library that helps with the truncation of text in Vue apps.

There are several advantages to using vue-clamp to truncate text in a Vue.js app:

  1. Easy to use: vue-clamp is a simple and easy-to-use library, with a straightforward API that allows you to quickly set up text truncation
  2. Customizable: vue-clamp provides a number of customization options, such as the ability to set the maximum number of lines that should be displayed before truncation, and the text and styling of the “Read more” link
  3. Responsive: vue-clamp is designed to be responsive, so it can automatically adjust the truncation of text based on the available screen size
  4. Lightweight: vue-clamp is a lightweight library that has minimal impact on the performance of your Vue app

In order to show elaborate examples of vue-clamp in action, we’ll build a small Vue app that displays a couple of blog posts.

N.B., we’ll build this application using Vue 2 because the vue-clamp package is compatible with Vue 2. There is a different package that is compatible with Vue 3: vue3-text-clamp.

First, let’s install the Vue-CLI by running the following command:

npm install -g @vue/cli

Once the installation is complete, we can create a new Vue project by running this command:

vue create v-clamp-tut

Proceed as usual and select the options you would like to have, making sure to select 2.x when asked for the Vue version.

In the router/index.js file, update its contents to look as follows:

import Vue from "vue";
import VueRouter from "vue-router";
// import HomeView from "../views/HomeView.vue";
import PostView from "../views/PostView.vue";
import SinglePost from "../views/SinglePost.vue";
Vue.use(VueRouter);
const routes = [
  {
    path: "/post",
    name: "home",
    component: PostView,
  },
  {
    path: "/post/:id",
    name: "singlePost",
    component: SinglePost,
  },
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});
export default router;

The above lines of code take care of the routing in our Vue application.

Next, create an index.js file in the store directory and place the following lines of code in it:

export const posts = [
  {
    id: "1",
    author: "Jane Doe",
    description: "A post about the benefits of meditation",
    content:
      "Meditation has been shown to have a number of benefits for both the mind and the body. It can reduce stress and anxiety, improve focus and concentration, and even help to lower blood pressure. In this post, we'll explore some of the science behind meditation and how you can get started with a daily practice.",
    photo: "https://blog.logrocket.com/wp-content/uploads/2020/11/rust-grpc-tonic.png",
    featured: true,
  },
  {
    id: "2",
    author: "John Smith",
    description: "A guide to creating a successful morning routine",
    content:
      "Starting your day off on the right foot can set the tone for the rest of the day. In this post, we'll go over some tips for creating a morning routine that will help you feel energized, productive, and ready to tackle the day ahead. From exercise and meditation to making your bed and setting goals, we've got you covered.",
    photo: "https://images.unsplash.com/photo-1591035897819-f4bdf739f446?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTB8fGhhcHB5fGVufDB8fDB8fA%3D%3D&auto=format&fit=crop&w=500&q=60",
    featured: false,
  },
  {
    id: "3",
    author: "Sara Johnson",
    description: "The importance of self-care for busy professionals",
    content:
      "In today's fast-paced world, it's easy to get caught up in the hustle and forget to take care of ourselves. But self-care is crucial for maintaining our physical, mental, and emotional health. In this post, we'll explore some simple self-care strategies that busy professionals can incorporate into their daily routines. With cold and flu season in full swing, it's important to take steps to boost our immune systems. In this post, we'll go over five natural ways to support your body's natural defenses, including eating a healthy diet, getting enough sleep, and reducing stress. By following these tips, you can help keep yourself healthy and feeling your best.",
    photo: "https://images.unsplash.com/photo-1524250502761-1ac6f2e30d43?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTZ8fGhhcHB5fGVufDB8fDB8fA%3D%3D&auto=format&fit=crop&w=500&q=60",
    featured: true,
  },
  {
    id: "4",
    author: "Emily Williams",
    description: "5 ways to boost your immune system naturally",
    content:
      "With cold and flu season in full swing, it's important to take steps to boost our immune systems. In this post, we'll go over five natural ways to support your body's natural defenses, including eating a healthy diet, getting enough sleep, and reducing stress. By following these tips, you can help keep yourself healthy and feeling your best.",
    photo: "https://images.unsplash.com/photo-1489710437720-ebb67ec84dd2?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTd8fGhhcHB5fGVufDB8fDB8fA%3D%3D&auto=format&fit=crop&w=500&q=60",
    featured: false,
  },
  {
    id: "5",
    author: "Alex Thompson",
    description: "The benefits of journaling for mental health",
    content:
      "Journaling has long been recognized as a powerful tool for self-reflection and personal growth. In this post, we'll look at the science behind why journaling is so beneficial for mental health and provide some tips for getting started with your own journaling practice.",
    photo: "https://images.unsplash.com/photo-1519834785169-98be25ec3f84?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MjF8fGhhcHB5fGVufDB8fDB8fA%3D%3D&auto=format&fit=crop&w=500&q=60",
    featured: true,
  },
  {
    id: "6",
    author: "Laura Davis",
    description: "The best plant-based protein sources",
    content:
      "If you're trying to incorporate more plant-based protein into your diet, you're in luck! There are plenty of delicious and nutritious options to choose from. In this post, we'll go over some of the best plant-based protein sources, including beans, lentils, tofu, and more. Plus, we'll include some tasty recipe ideas to help you get started.",
    photo: "https://images.unsplash.com/photo-1657664073337-31394d7e5c7a?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8NXx8aGFwcHl8ZW58MHx8MHx8&auto=format&fit=crop&w=500&q=60",
    featured: false,
  },
];

This file will help us with the data rendered on the Vue frontend as we won’t make any real API calls.

Finally, create two files in the views folder: PostView.vue and SinglePost.vue.

In the PostView.vue file, add the following code:

<template>
  <div class="home">
    <h1>All Posts</h1>
  </div>
</template>

<style>
</style>

<script>
import { posts } from "../store/articles.js";
export default {
  name: "PostView",
  components: {},
  data: function () {
    return {};
  },
  methods: {},
  computed: {},
};
</script>

And in the SinglePost.vue file, add this code:

<template>
  <div class="home">
    <div class="homeContainer">
      <h1>Single Post</h1>
      <hr />
    </div>
  </div>
</template>
<style>
</style>
<script>
import { posts } from "../store/articles.js";
export default {
  name: "SinglePost",
  components: {
  },
  data: () => {
    return {};
  },
  methods: {},
  created() {},
};
</script>

Importing and installing vue-clamp in a Vue application

First, let’s start by installing the vue-clamp library. You can do this by running the following command in your terminal:

npm install vue-clamp

Once the library is installed, we’ll need to import it into the Vue component. We can do this by adding the following lines to the component’s script tag:

import VClamp from "vue-clamp";

export default {
...
  components: {
    VClamp,
  },
...
}

Finally, we use the v-clamp component in our component’s template:

<v-clamp></v-clamp>

Using vue-clamp to truncate text

Now that we’ve installed the vue-clamp library, let’s see how to use it to carry out basic text truncation in a Vue app.

First, update the contents of the PostView.vue file with the following lines of code:

<template>
  <div class="home">
    <h1>All Posts</h1>
    <div class="homeContainer">
      <div v-for="(post, i) of articles" :key="i" class="articles">
        <img class="thumbnail" :src="`${post.photo}`" alt="" />
        <div class="text-content">
          <h3>{{ post.description }}</h3>
          <!-- clamping post content -->
          <v-clamp autoresize :max-lines="max_lines" ellipsis="..." location="end">
            {{ post.content }}
          </v-clamp>
          <router-link :to="`/post/${post.id}`">
            <button class="button">Read</button>
          </router-link>
        </div>
      </div>
    </div>
  </div>
</template>
<style>
.homeContainer {
  width: 60%;
  margin: 0px auto;
  /* border: 1px solid black; */
}
.articles {
  display: flex;
  flex-direction: row;
  margin: 2em;
  align-items: center;
}
.thumbnail {
  width: 100px;
  height: 100px;
  display: inline;
}
.text-content {
  text-align: left;
  margin: 0 0 0 1em;
}
.button {
  padding: 0.5em;
}
.tags {
  background-color: rgb(33, 33, 180);
  border-radius: 50px;
  border: 0px;
  color: white;
  padding: 0.5em;
  margin-right: 2px;
}
</style>
<script>
import VClamp from "vue-clamp";
import { posts } from "../store/articles.js";
export default {
  name: "PostView",
  components: {
    VClamp,
  },
  data: function () {
    return {
      articles: posts,
      max_lines: 2,
     };
  }
};
</script>

The code snippet above iterates through the posts in store/articles.js, then displays the appropriate data. The text displayed between the <v-clamp> tag is truncated appropriately.

vue-clamp allows modifications to the display of the truncated text using props. Here are some of the allowed props and their functionalities:

Prop Use Default Values
max-line Allows us to specify how many lines we want the truncated text to span Any number
ellipsis Allows us to specify the particular ellipsis we wish to use to specify truncated text ‘…’ Any string
location Specifies where text should be truncated from ‘start’ ‘start’

Advanced techniques for customizing truncation with vue-clamp

Slots

vue-clamp also allows us to modify the behavior of the clamp using slots. vue-clamp provides before and after slots. The effects of the before slot are seen before the clamped text and the results of the after slot are seen after the clamped text.



To see scenarios of these slots, let’s add slots to the <v-clamp> in our PostView.vue and singlePost.vue views.

In PostView.vue, update the <v-clamp> tag as follows:

...
<v-clamp
  autoresize
  :max-lines="max_lines"
  ellipsis="..."
  location="end"
>
  {{ post.content }}
  <template v-if="post.featured" #before>
    <button class="tags">Featured</button>
  </template>
  <template #after="{ toggle, clamped }">
    <button @click="toggle">
      {{ clamped == true ? "see more" : "see less" }}
    </button>
  </template>
</v-clamp>
...

The result of the above code can be seen in the image below:

Vue-clamp Example Using Slots

 

The Featured tag is displayed using the before slot while the see more/see less button is displayed using the after slot.

Slot scopes

Slot scopes allow for the passing of state from the parent to the slots. vue-clamp has a couple of slots that allow us to use the state of the parent clamp in the before and after slots:

...
  <template #after="{ toggle, clamped, expanded, expand, collapse }">
    ...
  </template>
...

These slot scopes are useful because we can have data on the state of each clamped text. So we can do things like toggle the clamped state of a single text without affecting others, and change what our expand buttons say for a single clamped text. In a nutshell, these slot scopes help to scope events to each clamped text.

In SinglePost.vue, update its entire contents with the following code:

<template>
  <div class="home">
    <div class="homeContainer">
      <h1>{{ post.description }}</h1>
      <img alt="Vue logo" :src="`${post.photo}`" />
      <div class="text-content">
        <v-clamp autoresize :max-lines="max_lines">
          {{ post.content }}
          <template #after="{ toggle, clamped, expanded }">
            <button v-if="clamped == true || expanded == true" @click="toggle">
              {{ clamped == true ? "see more" : "see less" }}
            </button>
          </template>
        </v-clamp>
      </div>
      <hr />
    </div>
  </div>
</template>
<style>
.homeContainer {
  width: 60%;
  margin: 0px auto;
  /* border: 1px solid black; */
}
.text-content {
  text-align: left;
  margin: 2em 0 0 1em;
}
.button {
  padding: 0.5em;
}
</style>
<script>
import VClamp from "vue-clamp";
import { posts } from "../store/articles.js";
export default {
  name: "SinglePost",
  components: {
    VClamp,
  },
  data: () => {
    return {
      max_lines: 3,
    };
  },
  methods: {},
  created() {
    this.id = this.$route.params.id;
    this.post = posts.find((el) => el.id == this.id);
  },
};
</script>

In the code block above, using the created() lifecycle method, we fetched a single post and displayed its contents. Within the <v-clamp>, we’re using an after slot to check for the clamped state of the text and then displaying the appropriate button.

Clampchange events

vue-clamp provides a clampchange event that allows us to perform an action when the clamp state changes from clamped to expanded and vice versa. It gives a clamped callback with a Boolean value depending on the current clamped state:

...
  <v-clamp autoresize :max-lines="max_lines" @clampchange="changed">
  ...
  </v-clamp>
...

//inside your script
...
  methods: {
      changed(clamped) {
        console.log("clamped", clamped);
      },
    },
...

In the code snippet above, we console.log the current clamped state of the text within the <v-clamp> tag, in order to see what it returns. If the clamped stated is toggled, its new state is printed out to the console.

And there we have it! We were able to build a blog application using vue-clamp and gain an understanding of advanced techniques, including slots, slot scopes, and events.

Conclusion

In this article, we learned how to simplify the process of truncating text in Vue apps using the vue-clamp library.

As a recap, truncating text can be useful in a Vue.js app for several reasons:

  1. To improve the layout of the app: Truncating text can help you fit more content into a smaller space, making it easier to design a clean and organized layout
  2. To improve readability: Truncating long blocks of text can make it easier for users to scan and read the contents of a page
  3. To improve performance: Truncating text can also improve the performance of your Vue.js app, as it reduces the amount of content that needs to be loaded and rendered on the page

Check out this GitHub repo containing the complete code for this article.

Experience your Vue apps exactly how a user does

Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens in your Vue apps including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.

The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred.

Modernize how you debug your Vue apps - .

Alexander Godwin I'm a software developer and writer that likes to write code and build things. Currently I'm fascinated by distributed systems and cloud computing.

Leave a Reply