react-tabtab-next
A mobile support, draggable, editable and api based Tab for ReactJS
(!) This lib based on react-tabtab but refactored using Typescript and replacing some deprecated libsDemo Page
Demo Playground
<img src="./docs/demo.gif" width="100%" >
for build a local playground run
npm run demo
also here Codesandbox playground
Features
- Mobile supported — Touch support. Easy to use on mobile device
- Draggable tab — Support drag and drop tab
- Add & Delete — Tab can be added and deleted
- Async content — Lazy load panel content
- Customizable style — Based on
styled-components
, super easy to customize tab style - API based — All actions are controllable
- ARIA accessible
Table of Contents
- [Minimal setup](#minimal-setup)
- [Draggable tab](#draggable-tab)
- [Async Panel](#async-panel)
- [Another Examples](#another-examples)
Installation
Install it with npm or yarnnpm install @react-tabtab-next/tabtab --save
Then, import the module by module bundler like
webpack
, browserify
// es6
import { Tabs, DragTabList, PanelList, Panel, ExtraButton } from '@react-tabtab-next/tabtab';
// not using es6
var Tabtab = require('react-tabtab');
var Tabs = Tabtab.Tabs;
Usage
React-tabtab is a tab component with highly customization. You can create a tab in simply setting. You also can create a tab system full withdraggable
, async loading
, close and create button
.
All the actions are api based. It means there is no state
in the component. Developers have full control.Minimal setup
import React from 'react';
import { Tabs, Panel, Tab, TabList, PanelList } from '@react-tabtab-next/tabtab';
export const Example = () => {
return (
<Tabs>
<TabList>
<Tab>Tab1</Tab>
<Tab>Tab2</Tab>
</TabList>
<PanelList>
<Panel>Content1</Panel>
<Panel>Content2</Panel>
</PanelList>
</Tabs>
);
};
It's simple to use. Zero configuration!
Draggable tab
import React, { Component } from 'react';
import { Tabs, DragTabList, PanelList, Panel, Tab, helpers } from '@react-tabtab-next/tabtab';
const makeData = (number, titlePrefix = 'Tab') => {
const data = [];
for (let i = 0; i < number; i++) {
data.push({
title: `${titlePrefix} ${i}`,
content: <div>Content {i}</div>,
});
}
return data;
};
export default class Drag extends Component {
constructor(props) {
super(props);
this.handleTabChange = this.handleTabChange.bind(this);
this.handleTabSequenceChange = this.handleTabSequenceChange.bind(this);
const tabs = makeData(10, 'Some Tab');
this.state = {
activeIndex: 0,
tabs,
};
}
handleTabChange(index) {
this.setState({ activeIndex: index });
}
handleTabSequenceChange({ oldIndex, newIndex }) {
const { tabs } = this.state;
const updateTabs = helpers.simpleSwitch(tabs, oldIndex, newIndex);
this.setState({ tabs: updateTabs, activeIndex: newIndex });
}
render() {
const { tabs, activeIndex } = this.state;
const tabsTemplate = [];
const panelTemplate = [];
tabs.forEach((tab, index) => {
tabsTemplate.push(<Tab key={index}>{tab.title}</Tab>);
panelTemplate.push(<Panel key={index}>{tab.content}</Panel>);
});
return (
<Tabs
activeIndex={activeIndex}
onTabChange={this.handleTabChange}
onTabSequenceChange={this.handleTabSequenceChange}
customStyle={this.props.customStyle}
>
<DragTabList>{tabsTemplate}</DragTabList>
<PanelList>{panelTemplate}</PanelList>
</Tabs>
);
}
}
ReactDOM.render(<Drag />, document.getElementById('root'));
Based on above example, the different to implement
normal tab
or drag tab
is using different wrapper and child.And all the actions are controllable. You can customize your switch action. But if you don't want to write customized switch logic, you can directly use
import {simpleSwitch} from 'react-tabtab/lib/helpers/move'
this built-in function.normal tab
<Tabs>
<TabList>
<Tab>Tab1</Tab>
<Tab>Tab2</Tab>
</TabList>
<PanelList>
<Panel>Content1</Panel>
<Panel>Content2</Panel>
</PanelList>
</Tabs>
Sortable tabs (+ ExtraButton)
<Tabs
// customStyle={md}
// activeIndex={activeTab}
// onTabChange={handleOnTabChange}
// onTabSequenceChange={handleOnTabSequenceChange}
ExtraButton={
<ExtraButton
onClick={(e) => {
console.log(e);
}}
>
+
</ExtraButton>
}
>
<DragTabList>
<Tab>Tab1</Tab>
<Tab>Tab2</Tab>
</DragTabList>
<PanelList>
<Panel>Content1</Panel>
<Panel>Content2</Panel>
</PanelList>
</Tabs>
Async Panel
In some case, if the data is large or we want to save the bandwidth, lazy loading the content is possible solution. You can useAsyncPanel
to laze load panel content.
Moreover, you can mix lazy load panel with normal panel!import React from 'react';
import { Tabs, Panel, Tab, TabList, PanelList, AsyncPanel } from '@react-tabtab-next/tabtab';
const AsyncTabsExmple = () => {
const loadContentFunc = (callback) => {
setTimeout(() => {
callback(null, 'some content');
}, 1000);
};
return (
<Tabs>
<TabList>
<Tab>Tab1</Tab>
<Tab>Tab2</Tab>
</TabList>
<PanelList>
<Panel>Content1</Panel>
<AsyncPanel
loadContent={loadContentFunc}
render={(data) => <div>{JSON.stringify(data)}</div>}
renderLoading={() => <div>Loading...</div>}
cache={true}
/>
</PanelList>
</Tabs>
);
};
export default AsyncTabsExmple;
To implement lazy loading, use
AsyncPanel
to wrap your panel content. Remember to provide loadContent
, render
, renderLoading
these 3 props.In
loadContent
props, both callback
and promise
type are supported.If you use
callback
, remember to call callback
when finish async loading.If you use
promise
, need to return promise action.When data is loading, the panel content will show
renderLoading
component.After finishing loading data, the panel content will show
render
component and react-tabtab will pass the loadContent
result as first parameter. So you can customize the component of panel content.Another Examples
More code examples are avalable here.Components / Api
<Tabs />
<Tabs/>
is the main component of react-tabtab
. Most of the api is passed from it.<TabList />
Use to wrap<Tab/>
.<DragTabList />
Use to wrap<Tab/>
.<Tab />
Normal Tab. Show the children component on tab.Example
<Tab>
<i className="fa fa-map-pin"></i>
map tab
</Tab>
<PanelList/ >
Use to wrap<Panel/>
<Panel />
Tab content.<AsyncPanel />
Lazy loading panel content.Customize style
react-tabtab-next
is based on styled-components
. Therefore, it's super easy to customize the tab style.Just extend the default component style and pass it to
customStyle
props.Use current style
Install tabtab themesnpm install @react-tabtab-next/themes --save
Available themes:
md
, bootstrap
, bulma
For example, if you want to use
material-design
, import the style and pass to customStyle
props.Example:
import React, { Component } from 'react';
import { Tabs, TabList, Tab, PanelList, Panel } from '@react-tabtab-next/tabtab';
import { md } from '@react-tabtab-next/themes';
export default class Customized extends Component {
render() {
return (
<Tabs customStyle={md}>
<TabList>
<Tab>Tab1</Tab>
<Tab>Tab2</Tab>
</TabList>
<PanelList>
<Panel>Content1</Panel>
<Panel>Content2</Panel>
</PanelList>
</Tabs>
);
}
}
And now your tab is material design style!
Make your own style
If current theme doesn't meet your demand, follow this three steps and create a new one.- First step: import current style
import styled from 'styled-components';
import { styled as styledTabTab } from '@react-tabtab-next/tabtab';
let { TabListStyle, ActionButtonStyle, TabStyle, PanelStyle } = styledTabTab;
- Second: extend style and export it
import styled from 'styled-components';
import { styled as themeStyled } from '@react-tabtab-next/tabtab';
let { TabList, ActionButton, Tab, Panel } = themeStyled;
TabList = styled(TabList)`
background-color: transparent;
line-height: 1.2;
border: 0;
`;
Tab = styled(Tab)`
padding: 1px 10px;
position: relative;
font-size: 12px;
text-transform: uppercase;
border: 0;
background: transparent;
${(props) => {
return props.active && !props.vertical
? `
border-bottom: 2px solid #ce93d8;
`
: null;
}}
&:hover .tab-label_close-button {
opacity: 1;
}
&:hover {
color: unset;
background: #89898920;
}
`;
ActionButton = styled(ActionButton)`
background-color: transparent;
border-radius: 0;
border: none;
opacity: 0.3;
transition: opacity 0.2s;
& svg {
font-size: 21px;
padding: 0;
}
&:hover {
opacity: 1;
}
`;
Panel = styled(Panel)``;
export { TabList, ActionButton, Tab, Panel };
- Last: import your style and use it!
When you finish the new
@react-tabtab-next/theme
style, feel free to add it to theme/
folder and send PR!Development
npm i
npm run demo
or
yarn install
yarn demo
Build the bundle
npm i