GithubHelp home page GithubHelp logo

spatie / vue-tabs-component Goto Github PK

View Code? Open in Web Editor NEW
621.0 621.0 205.0 250 KB

An easy way to display tabs with Vue

Home Page: http://vue-tabs-component.spatie.be

License: MIT License

JavaScript 57.44% Vue 42.56%
component javascript tabs ui vue

vue-tabs-component's Introduction

🚨 THIS PACKAGE HAS BEEN ABANDONED 🚨

We don't use this package anymore in our own projects and cannot justify the time needed to maintain it anymore. That's why we have chosen to abandon it. Feel free to fork our code and maintain your own copy.

A Vue component to easily render tabs

Latest Version on NPM Software License Build Status npm

The package contains a Vue component to easily display some tabs.

This is how they can be used:

<div>
    <tabs :options="{ useUrlFragment: false }" @clicked="tabClicked" @changed="tabChanged">
        <tab name="First tab">
            This is the content of the first tab
        </tab>
        <tab name="Second tab">
            This is the content of the second tab
        </tab>
        <tab name="Disabled tab" :is-disabled="true">
            This content will be unavailable while :is-disabled prop set to true
        </tab>
        <tab id="oh-hi-mark" name="Custom fragment">
            The fragment that is appended to the url can be customized
        </tab>
        <tab prefix="<span class='glyphicon glyphicon-star'></span> " 
             name="Prefix and suffix" 
             suffix=" <span class='badge'>4</span>">
            A prefix and a suffix can be added
        </tab>
    </tabs>
</div>

When reloading the page the component will automatically display the tab that was previously opened.

The rendered output adheres to the ARIA specification.

Demo

You can see a demo here: http://vue-tabs-component.spatie.be

Installation

You can install the package via yarn:

yarn add vue-tabs-component

or npm:

npm install vue-tabs-component --save

Usage

The most common use case is to register the component globally.

//in your app.js or similar file
import Vue from 'vue';
import {Tabs, Tab} from 'vue-tabs-component';

Vue.component('tabs', Tabs);
Vue.component('tab', Tab);

Alternatively you can do this to register the components:

import Tabs from 'vue-tabs-component';

Vue.use(Tabs);

On your page you can now use html like this to render tabs:

<div>
    <tabs>
        <tab name="First tab">
            First tab content
        </tab>
        <tab name="Second tab">
            Second tab content
        </tab>
        <tab name="Third tab">
            Third tab content
        </tab>
    </tabs>
</div>

By default it will show the first tab.

If you click on a tab a href representation of the name will be append to the url. For example clicking on the tab Second tab will append #second-tab to the url.

When loading a page with a fragment that matches the href of a tab, it will open up that tab. For example visiting /#third-tab will open up the tab with name Third tab.

Remembering the last opened tab

By default the component will remember which was the last open tab for 5 minutes . If you for instance click on Third tab and then visit / the third tab will be opened.

You can change the cache life time by passing the lifetime in minutes in the cache-lifetime property of the tabs component.

<tabs cache-lifetime="10">
  ...
</tabs>

Disable modifying the url fragment

When using with other libraries that use the url fragment, you can disable modifying the url fragment by passing the useUrlFragment options. This helps using it with vue-router, or using vue-tabs-component twice in the same page.

<tabs :options="{ useUrlFragment: false }">
  ...
</tabs>

Callbacks

Tabs has two events to which you can bind: changed and clicked

<tabs @clicked="tabClicked" @changed="tabChanged">
  ...
</tabs>
export default {
    ...
    methods: {
        ...
        tabClicked (selectedTab) {
            console.log('Current tab re-clicked:' + selectedTab.tab.name);
        },
        tabChanged (selectedTab) {
            console.log('Tab changed to:' + selectedTab.tab.name);
        },
        ...
    }
}

changed is emitted when the tab changes and can be used as handle to load data on request. clicked is emitted when an active tab is re-clicked and can be used to e.g. reload the data in the current tab.

Adding a suffix and a prefix to the tab name

You can add a suffix and a prefix to the tab by using the suffix and prefix attributes.

<tab prefix="my prefix - " name="First tab" suffix=" - my suffix">
    First tab content
</tab>

The title of the tab will now be my prefix - First tab - my suffix.

The fragment that's added to the url when clicking the tab will only be based on the name of a tab, the name-prefix and name-suffix attributes will be ignored.

Customizing fragments

When clicking on a tab it's name will be used as a fragment in the url. For example clicking on the Second tab will append #second-tab to the current url.

You can customize that fragment by using the id attribute.

<div>
    <tabs>
        <tab id="custom-fragment" name="My tab">
            First tab content
        </tab>
    </tabs>
</div>

Clicking on My tab will then append #custom-fragment to the url.

Setting a default tab

When disabling the cache, it can be useful to specify a default tab to load which is not the first one. You can select this by passing the defaultTabHash option.

<tabs :options="{ defaultTabHash: 'second-tab' }">
    <tab id="first-tab" name="First tab">
        First tab content
    </tab>
    <tab id="second-tab" name="Default tab">
        Second tab content
    </tab>
</tabs>

CSS

You can use the CSS from the docs as a starting point for your own styling. The output HTML has namespaced classes to target all nodes directly.

<div class="tabs-component">
    <ul class="tabs-component-tabs">
        <li class="tabs-component-tab">
            <a class="tabs-component-tab-a"></a>
        </li>
    </ul>
    <div class="tabs-component-panels">
        <section class="tabs-component-panel"></section>
    </div>
</div>

Changelog

Please see CHANGELOG for more information what has changed recently.

Testing

$ yarn test

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security related issues, please contact Freek Van der Herten instead of using the issue tracker.

Postcardware

You're free to use this package, but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using.

Our address is: Spatie, Samberstraat 69D, 2060 Antwerp, Belgium.

We publish all received postcards on our company website.

Credits

This package is based on the solution presented by Jeffrey Way in the practical example #3 video in the Vue series on Laracasts

Support us

Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects on our website.

Does your business depend on our contributions? Reach out and support us on Patreon. All pledges will be dedicated to allocating workforce on maintenance and new awesome stuff.

License

The MIT License (MIT). Please see License File for more information.

vue-tabs-component's People

Contributors

akoepcke avatar dissolve avatar freekmurze avatar jbtje avatar leksat avatar manelclos avatar matewiszt avatar pongoman avatar sebastiandedeyne avatar willemvb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vue-tabs-component's Issues

Typescript Support (Feature Request)

Hi,

Would you be able to add Typescript support into your next release. The code below creates a 'No declaration file ...' error and the same applies for global import into main.ts.

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import Tabs from 'vue-tabs-component';

@Component
export default class InitialSetupWizard extends Vue {
  @Prop() private msg!: string;
}
</script>

Many thanks,
Lee

Thank you

This is not an issue or bug, I just wanted to say thanks for this package. I started to write my own and I soon realized that there a bunch of edge cases on this sort of thing.

I used your package and i just worked. Even with my own css.

Thanks 👍

Working with axios

How to working active tabs with axios? tried to implement to alphabetical pagination but i don't have any idea even didn't have any documentation to work with script tag.

Scoped styles

if I use scoped styles in a vue file, then the styles have data-v, and the element does not have

<style lang="scss" scoped>
li.is-disabled a {
  color: red !important;
}
</style>

in browser:

.newPost .form .tabs-component ul.tabs-component-tabs li.is-disabled a[data-v-0de4e860] {
    color: red !important;
}
<li role="presentation" class="tabs-component-tab is-disabled">
  <a aria-controls="#" href="#" role="tab" class="tabs-component-tab-a">Photos</a>
</li>

Close button feature

I request a new feature, a close button look like a close button at Chrome Browser tab.

Include /dist directory

We use the old stack (Rails 3) and the only way for us to use these great components is by having .js file to be able to include it in a script tag.

I can run npm run build manually, however, sometimes it is not as straightforward as it should be, npm is npm. I've just spent 1 hour trying to figure out why builds are failing and it turned out that one of the libs became broken: beautifier/js-beautify#1247

It could be a time saver for me if I could have dist folder already in the repo.

Thanks for your great work! A postcard is coming! :)

Starting point css

When using vue-tabs-component, I copied the CSS form the example webpage and modified it to suit my needs. I was wondering if there is any official CSS that is shipped as a base for users to modify.

We had to move "list-style: none" into a more specific selector to be able to use it within Django admin. But I can't find any css code other than the one in docs folder, which is not referenced in the README, so no PR :)

.tabs-component-tabs {
  border: solid 1px #ddd;
  /*list-style: none;*/
  border-radius:  6px;
  margin-bottom: 5px;
}

.tabs-component-tabs li {
  list-style: none;
}

Inject Icons on the tab controls

Hi, I wonder how to add or customize the li anchor tags to have an icon or images. Is it possible to have an option like below?

<tab name="First tab" :icon="my-icon"> // custom icon only
<tab name="First tab" :image="src/to/icon"> // image only
<tab name="First tab" :image="src/to/icon" name="First tab"> // image with icon

Would love to have like this kind of option.
Thanks man!

Multiple tabs on the same page

I have to make 2 components on the same page, but tabs should have different styles. Is it possible to customize tabs not only with global css?

Add custom CSS class to tab header item

I can add custom CSS class to the component content, like this

<tabs :options="{ useUrlFragment: false }">
  <tab v-for="tab in tabs" :class="'some-cool-class'">
    <h3 v-html="tab.content.title"></h3>
    <p v-html="tab.content.description"></p>
  </tab>
</tabs>

But, how can I customize the tab header attributes?

Separating the tabs from the content?

Thank you for this component – it's really well-designed and thought out and I appreciate the work that's gone into it (particularly when JS is disabled).

My app has a requirement for a tab to be separate visually from its content (really, the "tab" is just a toggle that shows/hides another <div> elsewhere). This means I can't use this component as it currently works because its HTML structure doesn't work for me.

How much work would it be to modify this component to allow the tab content to be placed elsewhere in the DOM and link it somehow to the tab component? I'm still fairly new to Vue so uncertain if this would be impractical.

Change tab programmatically

Hello. Thanks for great package. Is it possible to change the tab programmatically by clicking on a link or button? thank you!

Using the library with a <script> tag

Hi,

I'm trying to use the library loading it using a <script> tag. First problem is that Tabs and Tab are not exported to the global scope. Second problem is that "vue-tabs" seems not to be a valid name. As a workaround I've changed webpack.config.js to name it "vuetabs" instead:

library: 'vuetabs',

and use it like:

  var Tabs = vuetabs.Tabs;
  var Tab = vuetabs.Tab;

  new Vue({
      components: {
        Tabs,
        Tab
      },
      ...

What's the correct way to use it without needed these modifications?

Thanks!

Create tabs in runtime with vue-router

I'm wanting to make when the user chooses a left-side option to be created at the runtime rendering location (<router-view></router-view>) a tab containing the component of the route that he selected. It is possible? Do you have any examples? Does Component work well with vue-router?

How to $emit tab name to parent?

Right now My_Parent component pass array of tab, named tabA, to My_Child component. Then My_Chid component render a tab using 'vue-tabs-component'. What I am trying to do is to emit a 'selected tab' back to the parent component.

I have tried using @Changed in but it doesn't work. Could you please suggest me how to emit tab is whenever a tab is changed?

Thank you very much

Add icon component as prefix/suffix

Hi, Thanks for sharing this useful component.

There is this use case that I have a question about. We mostly use components to generate icons, like here.

How can I pass this icon/component to prefix?

Moving prefix and suffix to slot

Hello. Thanks for great package. But I want to offer you to move prefix and suffix content to slots. Since it can have HTML and become a bit complicated to handle dynamic things like counters.

If you like the idea I can take care about implementing it

.tabs-component-tab-a css attr

oh, .tabs-component-tab-a class you should be add css attr user-select:none, because the mouse will be selected when sliding

Allow inner nested tabs to not set anchors

I want to have tabs inside my tabs, but only the outside tabs should set the anchor.

I tried setting href='' on the inside tabs, hoping that would be a cue to not change the anchor, but it didn't work.

I was able to work-around by using jquery to take the href off of the the inner tabs.

It would be nice if setting href='' or a new property "no_anchor=true" would prevent the tab from updating the anchor.

problem when dynamic import change base href="/"

I've been trying very hard to get dynamic imports working, so that my vue components only get instantiated when they are actually requested on the page.

After some tinkering with webpack's config and doing a lot of reading. I found the fix that makes the problem go away. Simply add

<base href="/" />

in your and just like that my dynamic imports are now working. Looks hacky right? Well it was suggested in many threads:
laravel-mix/laravel-mix#484
webpack/webpack-dev-server#333
gaearon/react-hot-loader#620 (comment)

So I think to myself yay problem fixed! But then I realize that this package has stopped working!

When I add the <base href="/" />to my <head> then all my vue-tabs-component omit the current path when changing tabs and instead of appending the hashtag to the current url, it links to /#hashtag

So it always links to the root "/" and so the tabs don't work anymore at all

I tried enabling/disabling the new useUrlFragment option thinking it may fix it but unfortunately it doesn't seem to have any impact whether it's set to true or false

Any chance you can help with this problem? Ideally the behaviour should always be that it should append the hashtag to the current url.. regardless of anything

Thanks!

Dependencies

I'm having some trouble building locally and noticed some missing packages, I've added a few but haven't been able to determine all of them. What are all the dependencies? I'd be happy to add them and issue a pull request.

Tabs have no CSS

I'm new with Vue and Vue cli. I'd like to try out this tabs-component, and my code in App.vue is as follows:

<template>
  <div>
    <tabs>
        <tab name="First tab">
            First tab content
        </tab>
        <tab name="Second tab">
            Second tab content
        </tab>
        <tab name="Third tab">
            Third tab content
        </tab>
    </tabs>
  </div>
</template>

<script>
import Vue from 'vue';
import {Tabs, Tab} from 'vue-tabs-component';
Vue.component('tabs', Tabs);
Vue.component('tab', Tab);
export default {
  name: 'App'
}
</script>

In browser:
image

What can I do to fix it, please show me the way!

fix unset options prop issues is still an issue

the default() for options needs to return an object.

change this:
options: {
type: Object,
required: false,
default () {
useUrlFragment: true
},

},

to this:
options: {
type: Object,
required: false,
default () {
return { useUrlFragment: true }
},

},

changed event fires twice on each change

I'm running into a small issue with the "changed" event: every time a tab is changed, the event is emitted twice.

This seems to happen because selectTab() is actually called twice. It happens once directly via the click handler, and a second time due to the hashchange event listener.

It seems to me that we'd want to either let the click event handler initiate the change, OR the hashchange event handler, but not both. Also, I found at least one way to set the hash without triggering the hashchange event, which could be another approach.

I'm happy to put in the work with this, but I wanted to touch base first before offering a PR. I may be missing something here...

Very helpful component - thank you!

Changing url on tab selection

I'm trying to come up with a way of changing the url when selecting one of the tabs. So instead of a url fragment example.com/home#tab1, it would be example.com/home/tab1. Is this something which could be worked into the component?

Can't import vue-tabs-component

Hello, when I'm trying to import library: import Tabs from 'vue-tabs-component';
I see, Error: Cannot find module '../expiringStorage' from ...
What could be the problem?

Set active tab on load

I've been trying to figure out if there is a way to set what tab should be active on load in the template? I know that you can set it with the url fragment, but it doesn't really fit my use case.

Something like the code to disable a tab is-disabled="true" for example; is-active="true"

<tab name="First tab">
    First tab content
</tab>
<tab name="Second tab" :is-active="true">
    Second tab content
</tab>
<tab name="Third tab">
    Third tab content
</tab>

Or is there any other way to solve the same behavior?

disable turbolinks

Please add data-turbolinks=false on tab links.
On Rails application with turbolinks had bugs, page alwayse reloading when click on tab.

Component not working properly in IE

First of all, thanks a lot for the awesome component!

I've noticed that the component doesn't work properly in IE. I know it's kind of a pain to support IE 11 and I don't know if it is on the roadmap for your project, but for the project that I'm currently working on IE is still almost 12% of the visits :/

screen shot 2017-11-23 at 10 00 36

I'll try to see if I can solve it, and if I do I can submit a PR if you guys are interested in supporting IE.

Cheers!

Transitions

Hey.

I was playing around with this package and tried to get some nice transition for the tab’s content. Unfortunately, I couldn’t get it to work. I suspect that that we need to do is to wrap the actual code in the tab.vue file in a <transition> element which then we can define the appropriate classes for the transition itself.

Maybe what we can do is to accept a transition name as a prop of the <tab> element and wrap the whole component in a transition element.

Maybe there is a better way of doing it that I’m not aware of?

active on load in the template

I've been trying to figure out if there is a way to set what tab should be active on load in the template? I know that you can set it with the url fragment, but it doesn't really fit my use case.

Something like the code to disable a tab is-disabled="true" for example; is-active="true"

<tab name="First tab">
    First tab content
</tab>
<tab name="Second tab" :is-active="true">
    Second tab content
</tab>
<tab name="Third tab">
    Third tab content
</tab>

Or is there any other way to solve the same behavior?

Dependencies with browserify

I can't import your lib using browserify due to releative imports in your index.js (those files are not in the dist folder, they are in the src folder), e.g.:

// line 349
        factory(exports, require('../expiringStorage'));
// line 575
        factory(exports, require('./components/Tab'), require('./components/Tabs'));

pluggable storage

hey,

thanks for working on this :). It would be nice if the storage backend would be pluggable and could be replaced. the expiringStorage is probably a good fit for easier setups but in my case I’d like to control which tab is displayed. apart from that this would also open up the possibility to prevent tab changes.

i will probably start working on this today and if you’d like to have this feature I’ll prepare a pull request.

How can I apply custom CSS to this component?

From the README, I see that you can import css from node_modules/vue-tabs-component/docs/resources/tabs-component.css, and this works fine when I import the css globally in my index.js.

However, when I use Vue components, how can I apply custom styling to a tab component?

If I remove the reference to the tabs-component.css stylesheet from index.js, and just copy and paste the css you have into the <style scoped> tag of my Vue component, no styling to the tabs component is applied.

This is what my component looks like:

<template>
  <div class="pusher">
    <div class="ui middle aligned center aligned grid">
      <div class="column">
        <tabs>
          <tab name="Personal">
            This is the personal tab
          </tab>
          <tab name="World">
            This is the world tab
          </tab>
        </tabs>
      </div>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'feed',
  };
</script>

<style>
  .tabs-component {
    margin: 4em 0;
  }

  .tabs-component-tabs {
    border: solid 1px #ddd;
    border-radius: 6px;
    margin-bottom: 5px;
  }

  @media (min-width: 700px) {
    .tabs-component-tabs {
      border: 0;
      align-items: stretch;
      display: flex;
      justify-content: flex-start;
      margin-bottom: -1px;
    }
  }

  .tabs-component-tab {
    color: #999;
    font-size: 14px;
    font-weight: 600;
    margin-right: 0;
    list-style: none;
  }

  .tabs-component-tab:not(:last-child) {
    border-bottom: dotted 1px #ddd;
  }

  .tabs-component-tab:hover {
    color: #666;
  }

  .tabs-component-tab.is-active {
    color: #000;
  }

  .tabs-component-tab.is-disabled * {
    color: #cdcdcd;
    cursor: not-allowed !important;
  }

  @media (min-width: 700px) {
    .tabs-component-tab {
      background-color: #fff;
      border: solid 1px #ddd;
      border-radius: 3px 3px 0 0;
      margin-right: .5em;
      transform: translateY(2px);
      transition: transform .3s ease;
    }

    .tabs-component-tab.is-active {
      border-bottom: solid 1px #fff;
      z-index: 2;
      transform: translateY(0);
    }
  }

  .tabs-component-tab-a {
    align-items: center;
    color: inherit;
    display: flex;
    padding: .75em 1em;
    text-decoration: none;
  }

  .tabs-component-panels {
    padding: 4em 0;
  }

  @media (min-width: 700px) {
    .tabs-component-panels {
      border-top-left-radius: 0;
      background-color: #fff;
      border: solid 1px #ddd;
      border-radius: 0 6px 6px 6px;
      box-shadow: 0 0 10px rgba(0, 0, 0, .05);
      padding: 4em 2em;
    }
  }
</style>

I see that the generated HTML just renders divs with those classes applied, but this styling doesn't get applied. How can I apply custom CSS to the tabs component?

Javascript error if useUrlFragment not specified

Hey there,

I'm not sure if it's intentional to require useUrlFragment to be specified or not, but if I do not specify anything, I get Javascript errors in the console anytime I click a tab:

Uncaught TypeError: Cannot read property 'useUrlFragment' of undefined at VueComponent.selectTab

If I specify it, everything works fine.
<tabs cache-lifetime="120" :options="{ useUrlFragment: false }">
and
<tabs cache-lifetime="120" :options="{ useUrlFragment: true }">

both work fine.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.