npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@todovue/tv-sidebar

v2.1.1

Published

A versatile sidebar component for TODOvue, offering customizable layouts, themes, and responsive design options.

Readme

TODOvue Sidebar (TvSidebar)

A versatile and flexible Vue 3 sidebar component with multiple display modes: lists, categories (labels), and images. Perfect for blogs, documentation sites, and web applications requiring sidebar navigation or content display. Compatible with both SPA and SSR environments (e.g. Nuxt 3).

npm Netlify Status npm downloads npm total downloads License Release Date Bundle Size Node Version Last Commit Stars

Demo: https://tv-sidebar.netlify.app/


Table of Contents


Features

  • Three display modes: List, Categories (labels), and Image
  • Event-driven interactions: No built-in navigation; emits click events with full objects
  • Item limit: Control how many items to display with the limit prop
  • Optional clickable images: Enable with clickable to emit click events for images
  • Label/Category support: Display colored category labels with click events
  • Responsive design: Adapts to different screen sizes
  • SSR compatible: Works seamlessly in Nuxt 3 and SSR contexts
  • Customizable styling: Built with SCSS for easy theming
  • Tree-shakeable: Vue marked as external dependency

Installation

Using npm:

npm install @todovue/tv-sidebar

Using yarn:

yarn add @todovue/tv-sidebar

Using pnpm:

pnpm add @todovue/tv-sidebar

Note: This component depends on @todovue/tv-label for the categories mode.


Quick Start (SPA)

Global registration (main.js / main.ts):

import { createApp } from 'vue'
import App from './App.vue'
import TvSidebar from '@todovue/tv-sidebar'
import '@todovue/tv-sidebar/style.css' // import styles
import '@todovue/tv-label/style.css' // import styles

createApp(App)
  .use(TvSidebar) // enables <TvSidebar /> globally
  .mount('#app')

Local import inside a component:

<script setup>
import { TvSidebar } from '@todovue/tv-sidebar'
import '@todovue/tv-sidebar/style.css' // import styles
import '@todovue/tv-label/style.css' // import styles

const sidebarData = {
  title: "Most Popular Blogs",
  list: [
    {
      id: 1,
      title: "10 Tips for Creating a Successful YouTube Channel",
      link: "/blog/youtube-tips",
    },
    {
      id: 2,
      title: "The Benefits of Meditation",
      link: "/blog/meditation",
    }
  ]
}
</script>

<template>
  <TvSidebar :data="sidebarData" />
</template>

Nuxt 3 / SSR Usage

Add the stylesheet to your nuxt.config.ts:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@todovue/tv-card/nuxt'
  ]
})

Create a plugin file: plugins/tv-sidebar.client.ts (or without .client suffix for SSR):

import { defineNuxtPlugin } from '#app'
import TvSidebar from '@todovue/tv-sidebar'

export default defineNuxtPlugin(nuxtApp => {
  nuxtApp.vueApp.use(TvSidebar)
})

Use anywhere (no router dependency required):

<script setup>
import { TvSidebar } from '@todovue/tv-sidebar'
</script>

Component Registration Options

| Approach | When to use | |---------------------------------------------------------------------|------------------------------------------------| | Global via app.use(TvSidebar) | Many usages across app / design system install | | Local named import { TvSidebar } | Isolated / code-split contexts | | Direct default import import TvSidebar from '@todovue/tv-sidebar' | Single usage or manual registration |


Props

| Prop | Type | Default | Description | |-----------|---------|---------|------------------------------------------------------------------------------------------------------------------------------------------| | data | Object | {} | Main data object containing title and content (list, labels, or image). | | isImage | Boolean | false | Enables image display mode. | | isLabel | Boolean | false | Enables categories/labels display mode. | | limit | Number | 0 | Maximum number of items to display (0 = show all). | | clickable | Boolean | false | When true and isImage, the image becomes interactive and emits a click event with the image object. When false, image is static. |


Events

| Event name (kebab) | Emits (camel) | Description | |--------------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------| | clickLabel | clickLabel | Emitted when a label/category is clicked (also emits click with same object). | | click | click | Emitted when a list item is clicked, when a label is clicked, and when an image is clicked (if clickable). The payload is always the full object. |

Usage:

<TvSidebar 
  isLabel 
  :data="categoriesData" 
  @clickLabel="handleCategoryClick"
  @click="handleAnyClick"
/>

Usage Examples

Default List Mode

Display a numbered list of items that emit the full object on click:

<script setup>
import { TvSidebar } from '@todovue/tv-sidebar'

const listData = {
  title: "Most Popular Blogs",
  list: [
    {id: 1, title: "10 Tips for Creating a Successful YouTube Channel", link: "/blog/youtube-tips"},
    {id: 2, title: "The Benefits of Meditation and How to Get Started", link: "/blog/meditation"},
    {id: 3, title: "The Top 5 Destinations for Adventure Travel", link: "/blog/adventure-travel"}
  ],
}
function handleItemClick(item) {
  console.log('Item clicked:', item)
}
</script>

<template>
  <TvSidebar :data="listData" @click="handleItemClick" />
</template>

Categories (Labels) Mode

Display colored category labels:

<script setup>
import { TvSidebar } from '@todovue/tv-sidebar'

const categoriesData = {
  title: "Categories",
  labels: [
    {
      id: 1,
      name: "Vue.js",
      color: "#4FC08D",
    },
    {
      id: 2,
      name: "JavaScript",
      color: "#F0DB4F",
    },
    {
      id: 3,
      name: "HTML",
      color: "#E34F26",
    },
    {
      id: 4,
      name: "CSS",
      color: "#1572B6",
    }
  ]
}

function handleCategoryClick(category) {
  console.log('Category clicked:', category)
  // Navigate or filter by category
}
</script>

<template>
  <TvSidebar 
    isLabel 
    :data="categoriesData" 
    @clickLabel="handleCategoryClick"
  />
</template>

Image Mode

Display an image with title. Make it interactive with clickable if desired:

<script setup>
import { TvSidebar } from '@todovue/tv-sidebar'

const imageData = {
  title: "TODOvue Blog",
  image: {
    src: "https://todovue.com/vue.webp",
    alt: "TODOvue Logo",
    link: "https://todovue.com/"
  },
}
function handleImageClick(image) {
  console.log('Image clicked:', image)
}
</script>

<template>
  <!-- Non-clickable image -->
  <TvSidebar isImage :data="imageData" />
  
  <!-- Clickable image that emits the image object -->
  <TvSidebar isImage clickable :data="imageData" @click="handleImageClick" />
</template>

With Limit

Limit the number of displayed items:

<template>
  <!-- Show only first 5 items -->
  <TvSidebar :data="listData" :limit="5" />
  
  <!-- Show only first 8 categories -->
  <TvSidebar isLabel :data="categoriesData" :limit="8" />
</template>

Nuxt Integration

- Using with Nuxt routing:
- <TvSidebar linkTag="nuxt-link" :data="blogPosts" />

Nuxt works without router integration in the component. Handle navigation in your click handlers (see Navigation Handling below).


Data Structure

List Mode Data

{
  title: string,
  list: Array<{
    id: number | string,
    title: string,
    link?: string // optional; use in your click handler if you want to navigate
  }>
}

Labels/Categories Mode Data

{
  title: string,
  labels: Array<{
    id: number | string,
    name: string,
    color: string // Hex color code
  }>
}

Image Mode Data

{
  title: string,
  image: {
    src: string,    // Image URL
    alt: string,    // Alt text for accessibility
    link?: string   // optional; use in your click handler for manual navigation
  }
}

Styling

The component uses SCSS for styling. Styles are automatically included when you import the component. The sidebar includes:

  • Clean, minimal design
  • Responsive layout
  • Title with separator line
  • Hover effects on interactive items
  • Proper spacing and typography

To customize styles, you can override the CSS classes:

.tv-sidebar-body {
  /* Container styles */
}

.tv-sidebar {
  /* Main sidebar styles */
}

.tv-sidebar-title h1 {
  /* Title styles */
}

.tv-sidebar-content-li {
  /* List item styles */
}

Navigation Handling

Since the component does not perform navigation, handle it in your click handlers. Example with Vue Router:

<script setup>
import { TvSidebar } from '@todovue/tv-sidebar'
import { useRouter } from 'vue-router'

const router = useRouter()

const listData = {
  title: 'Recent Posts',
  list: [
    { id: 1, title: 'Getting Started with Nuxt 3', link: '/blog/nuxt-3' },
    { id: 2, title: 'Vue Composition API', link: '/blog/composition-api' }
  ]
}

function handleClick(item) {
  if (item?.link) router.push(item.link)
}
</script>

<template>
  <TvSidebar :data="listData" @click="handleClick" />
</template>

Accessibility

  • Semantic structure with clear headings
  • Alt text support for images
  • Interactive items emit click events; if you need keyboard accessibility, consider handling keydown (Enter/Space) on your side or wrapping with accessible elements/roles
  • Color contrast considerations for labels

SSR Notes

  • No direct DOM access (window / document) → safe for SSR
  • Compatible with Nuxt 3 out of the box
  • Styles are bundled and auto-imported
  • No router/nuxt-link dependency inside the component

Development

git clone https://github.com/TODOvue/tv-sidebar.git
cd tv-sidebar
npm install
npm run dev     # run demo playground
npm run build   # build library

Local demo served from Vite using index.html + src/demo examples.


Contributing

PRs and issues welcome. See CONTRIBUTING.md and CODE_OF_CONDUCT.md.


License

MIT © TODOvue


Dependencies

  • vue (^3.0.0) - Peer dependency
  • @todovue/tv-label - Used for category/label display mode

Attributions

Crafted with ❤️ for the TODOvue component ecosystem by Cristhian Daza