Tabs
Getting Started
Keep a look out on this space. Constantly adding more recipes over the next few months.
Give this repo a star, it will help out greatly!
- Vue Horizontal is required, and you need to install it .
- Recipes follow the design language defined in the design principle .
- You should be able to extract the code snippet and use it as a single file component.
- If you are consistently recycling a design pattern, you should abstract your SFC.
- It might look different on your website due various parent CSS rules. Tailwind is used under the hood with normalizing, that might be different from your default settings.
Recipes are designed:
- For the responsive web, using default breakpoints .
- For mobile first design,
peeking navigation
will be used on the mobile.
Assumption is made that you have a padding of 24px on the left and right on the mobile viewport.
The 24px is then removed and added into the
<vue-horizontal>
as scroll padding. - For broad usage pattern, you should take it and edit it your needs.
Why is it so complex? Why is it not shipped together with vue-horizontal?
- You control how to structure your content with HTML
- You control how it looks with CSS
- To give you greater control of your website and thus your code, vue-horizontal is merely a small component to horizontally align your content while fixing all the nasty quirks related to horizontal control (nav/scroll/touch). It also contains a few methods and event emitter that are optimized to make your life easier. It doesn't dictate how you structure your HTML or style your CSS. This responsive design logic is merely a skeleton of logic that is merely useful in that context. And every recipe may requires a different set of logic.
Tabs full width
Zoom: 50% | 100% →
import=recipes/tabs/recipes-tabs-simple.vue padding=0 zoom
<template>
<div>
<div class="tabs">
<vue-horizontal class="horizontal" :displacement="0.5" :button-between="false">
<template v-slot:btn-prev>
<svg class="btn-left" viewBox="0 0 24 24">
<path d="m9.8 12 5 5a1 1 0 1 1-1.4 1.4l-5.7-5.7a1 1 0 0 1 0-1.4l5.7-5.7a1 1 0 0 1 1.4 1.4l-5 5z"/>
</svg>
</template>
<template v-slot:btn-next>
<svg class="btn-right" viewBox="0 0 24 24">
<path d="m14.3 12.1-5-5a1 1 0 0 1 1.4-1.4l5.7 5.7a1 1 0 0 1 0 1.4l-5.7 5.7a1 1 0 0 1-1.4-1.4l5-5z"/>
</svg>
</template>
<div v-for="tab in tabs" :key="tab.name">
<div class="tab" :class="{selected: selected === tab.name}" @click="selected = tab.name">
{{ tab.name }}
</div>
</div>
</vue-horizontal>
</div>
<main>
<div v-for="tab in tabs" :key="tab.name" v-if="tab.name === selected">
<h1>{{ tab.content }}</h1>
<br>
<div>
<p>
Since tabs can be placed on the horizontal axis, and some might find it useful.
This is just a simple tabs design to showcase how you can use vue-horizontal for it.
When the screen is too small, vue-horizontal will automatically add navigation control if the screen is too
small.
</p>
<br>
<p>
As vue-horizontal is the main concern, this section is just an example how you can do tabs.
Ideally you should use vue-router to route to another page when the tab is selected.
</p>
<br>
<p>You might need to change your browser width to see the navigation control show up if your screen is too
wide.</p>
</div>
</div>
</main>
</div>
</template>
<script>
export default {
data() {
return {
tabs: [
{name: 'Home', content: 'Home Page Example'},
{name: 'For You', content: 'For You Page Example'},
{name: 'Trending', content: 'Trending Page Example'},
{name: 'Feed', content: 'Feed Page Example'},
{name: 'Gallery', content: 'Gallery Page Example'},
{name: 'Profile', content: 'Profile Page Example'},
{name: 'Friends', content: 'Friends Page Example'},
{name: 'Extra', content: 'Extra Page Example'},
{name: 'Setting', content: 'Setting Page Example'},
{name: 'Page Content 1', content: 'Page 1'},
{name: 'Page Content 2', content: 'Page 2'},
{name: 'Page Content 3', content: 'Page 3'},
{name: 'Page Content 4', content: 'Page 4'},
{name: 'Page Content 5', content: 'Page 5'},
{name: 'Page Content 6', content: 'Page 6'},
],
selected: 'Home'
}
}
}
</script>
<style scoped>
.btn-left, .btn-right {
padding: 8px;
height: 100%;
}
.btn-left {
background: linear-gradient(to left, #ffffff00 0, #fff 50%, #fff);
padding-right: 16px;
}
.btn-right {
background: linear-gradient(to right, #ffffff00 0, #fff 50%, #fff);
padding-left: 16px;
}
.tabs {
border-bottom: 1px solid #e2e8f0;
}
.tab {
padding: 8px 24px 6px 24px;
font-size: 17px;
font-weight: 600;
cursor: pointer;
}
.tab.selected {
border-bottom: 2px solid black;
}
main {
padding: 24px;
}
@media (min-width: 768px) {
main {
padding: 48px;
}
}
</style>
Tabs with fixed sides
Zoom: 50% | 100% →
import=recipes/tabs/recipes-tabs-sides.vue padding=0 zoom
<template>
<div>
<div class="header">
<div class="brand">
Brand
</div>
<vue-horizontal class="horizontal" :displacement="0.5" :button-between="false">
<template v-slot:btn-prev>
<svg class="btn-left" viewBox="0 0 24 24">
<path d="m9.8 12 5 5a1 1 0 1 1-1.4 1.4l-5.7-5.7a1 1 0 0 1 0-1.4l5.7-5.7a1 1 0 0 1 1.4 1.4l-5 5z"/>
</svg>
</template>
<template v-slot:btn-next>
<svg class="btn-right" viewBox="0 0 24 24">
<path d="m14.3 12.1-5-5a1 1 0 0 1 1.4-1.4l5.7 5.7a1 1 0 0 1 0 1.4l-5.7 5.7a1 1 0 0 1-1.4-1.4l5-5z"/>
</svg>
</template>
<div v-for="tab in tabs" :key="tab.name">
<div class="tab" :class="{selected: selected === tab.name}" @click="selected = tab.name">
{{ tab.name }}
</div>
</div>
</vue-horizontal>
<div class="option">
Filter
</div>
</div>
<main>
<div v-for="tab in tabs" :key="tab.name" v-if="tab.name === selected">
<h1>{{ tab.content }}</h1>
<br>
<div>
<p>
Since tabs can be placed on the horizontal axis, and some might find it useful.
This is just a simple tabs design to showcase how you can use vue-horizontal for it.
When the screen is too small, vue-horizontal will automatically add navigation control if the screen is too
small.
</p>
<br>
<p>
As vue-horizontal is the main concern, this section is just an example how you can do tabs.
Ideally you should use vue-router to route to another page when the tab is selected.
</p>
<br>
<p>You might need to change your browser width to see the navigation control show up if your screen is too
wide.</p>
</div>
</div>
</main>
</div>
</template>
<script>
export default {
data() {
return {
tabs: [
{name: 'Home', content: 'Home Page Example'},
{name: 'For You', content: 'For You Page Example'},
{name: 'Trending', content: 'Trending Page Example'},
{name: 'Feed', content: 'Feed Page Example'},
{name: 'Gallery', content: 'Gallery Page Example'},
{name: 'Profile', content: 'Profile Page Example'},
{name: 'Friends', content: 'Friends Page Example'},
{name: 'Extra', content: 'Extra Page Example'},
{name: 'Setting', content: 'Setting Page Example'},
{name: 'Page Content 1', content: 'Page 1'},
{name: 'Page Content 2', content: 'Page 2'},
{name: 'Page Content 3', content: 'Page 3'},
{name: 'Page Content 4', content: 'Page 4'},
{name: 'Page Content 5', content: 'Page 5'},
{name: 'Page Content 6', content: 'Page 6'},
],
selected: 'Home'
}
}
}
</script>
<style scoped>
.header {
display: flex;
border-bottom: 1px solid #e2e8f0;
}
.brand, .option {
flex-shrink: 0;
padding: 0 24px;
margin: 6px 0;
font-size: 18px;
font-weight: 700;
}
.horizontal {
flex-shrink: 1;
flex-grow: 1;
width: 50%;
}
.brand {
border-right: 1px solid #e2e8f0;
}
.option {
border-left: 1px solid #e2e8f0;
}
.btn-left, .btn-right {
padding: 8px;
height: 100%;
}
.btn-left {
background: linear-gradient(to left, #ffffff00 0, #fff 50%, #fff);
padding-right: 16px;
}
.btn-right {
background: linear-gradient(to right, #ffffff00 0, #fff 50%, #fff);
padding-left: 16px;
}
.tab {
padding: 8px 24px 6px 24px;
font-size: 17px;
font-weight: 600;
cursor: pointer;
}
.tab.selected {
border-bottom: 2px solid black;
}
main {
padding: 24px;
}
@media (min-width: 768px) {
main {
padding: 48px;
}
}
</style>