diff --git a/src/modules/Tab/Tab.js b/src/modules/Tab/Tab.js
index 9e2a57973f..3004f4ceda 100644
--- a/src/modules/Tab/Tab.js
+++ b/src/modules/Tab/Tab.js
@@ -3,10 +3,10 @@ import PropTypes from 'prop-types'
import React from 'react'
import {
- ModernAutoControlledComponent as Component,
customPropTypes,
getElementType,
getUnhandledProps,
+ useAutoControlledValue,
} from '../../lib'
import Grid from '../../collections/Grid/Grid'
import GridColumn from '../../collections/Grid/GridColumn'
@@ -18,21 +18,25 @@ import TabPane from './TabPane'
* @see Menu
* @see Segment
*/
-class Tab extends Component {
- getInitialAutoControlledState() {
- return { activeIndex: 0 }
+const Tab = React.forwardRef(function (props, ref) {
+ const { grid, menu, panes, menuPosition, renderActiveOnly } = props
+
+ const [activeIndex, setActiveIndex] = useAutoControlledValue({
+ state: props.activeIndex,
+ defaultState: props.defaultActiveIndex,
+ initialState: 0,
+ })
+
+ const handleItemClick = (e, { index }) => {
+ _.invoke(props, 'onTabChange', e, { ...props, activeIndex: index })
+ setActiveIndex(index)
}
- handleItemClick = (e, { index }) => {
- _.invoke(this.props, 'onTabChange', e, { ...this.props, activeIndex: index })
- this.setState({ activeIndex: index })
- }
-
- renderItems() {
- const { panes, renderActiveOnly } = this.props
- const { activeIndex } = this.state
+ const renderItems = () => {
+ if (renderActiveOnly) {
+ return _.invoke(_.get(panes, `[${activeIndex}]`), 'render', props)
+ }
- if (renderActiveOnly) return _.invoke(_.get(panes, `[${activeIndex}]`), 'render', this.props)
return _.map(panes, ({ pane }, index) =>
TabPane.create(pane, {
overrideProps: {
@@ -42,10 +46,7 @@ class Tab extends Component {
)
}
- renderMenu() {
- const { menu, panes, menuPosition } = this.props
- const { activeIndex } = this.state
-
+ const renderMenu = () => {
if (menu.tabular === true && menuPosition === 'right') {
menu.tabular = 'right'
}
@@ -54,55 +55,57 @@ class Tab extends Component {
autoGenerateKey: false,
overrideProps: {
items: _.map(panes, 'menuItem'),
- onItemClick: this.handleItemClick,
+ onItemClick: handleItemClick,
activeIndex,
},
})
}
- renderVertical(menu) {
- const { grid, menuPosition } = this.props
+ const renderVertical = (menuElement) => {
const { paneWidth, tabWidth, ...gridProps } = grid
- const position = menuPosition || (menu.props.tabular === 'right' && 'right') || 'left'
+ const position = menuPosition || (menuElement.props.tabular === 'right' && 'right') || 'left'
return (
{position === 'left' &&
- GridColumn.create({ width: tabWidth, children: menu }, { autoGenerateKey: false })}
+ GridColumn.create({ width: tabWidth, children: menuElement }, { autoGenerateKey: false })}
{GridColumn.create(
{
width: paneWidth,
- children: this.renderItems(),
+ children: renderItems(),
stretched: true,
},
{ autoGenerateKey: false },
)}
{position === 'right' &&
- GridColumn.create({ width: tabWidth, children: menu }, { autoGenerateKey: false })}
+ GridColumn.create({ width: tabWidth, children: menuElement }, { autoGenerateKey: false })}
)
}
- render() {
- const menu = this.renderMenu()
- const rest = getUnhandledProps(Tab, this.props)
- const ElementType = getElementType(Tab, this.props)
-
- if (menu.props.vertical) {
- return {this.renderVertical(menu)}
- }
+ const menuElement = renderMenu()
+ const rest = getUnhandledProps(Tab, props)
+ const ElementType = getElementType(Tab, props)
+ if (menuElement.props.vertical) {
return (
-
- {menu.props.attached !== 'bottom' && menu}
- {this.renderItems()}
- {menu.props.attached === 'bottom' && menu}
+
+ {renderVertical(menuElement)}
)
}
-}
+ return (
+
+ {menuElement.props.attached !== 'bottom' && menuElement}
+ {renderItems()}
+ {menuElement.props.attached === 'bottom' && menuElement}
+
+ )
+})
+
+Tab.displayName = 'Tab'
Tab.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
diff --git a/src/modules/Tab/TabPane.js b/src/modules/Tab/TabPane.js
index 0ecd3d2e73..4551dfb497 100644
--- a/src/modules/Tab/TabPane.js
+++ b/src/modules/Tab/TabPane.js
@@ -15,7 +15,7 @@ import Segment from '../../elements/Segment/Segment'
/**
* A tab pane holds the content of a tab.
*/
-function TabPane(props) {
+const TabPane = React.forwardRef(function (props, ref) {
const { active, children, className, content, loading } = props
const classes = cx(useKeyOnly(active, 'active'), useKeyOnly(loading, 'loading'), 'tab', className)
@@ -23,22 +23,24 @@ function TabPane(props) {
const ElementType = getElementType(TabPane, props)
const calculatedDefaultProps = {}
+
if (ElementType === Segment) {
calculatedDefaultProps.attached = 'bottom'
}
return (
-
+
{childrenUtils.isNil(children) ? content : children}
)
-}
+})
TabPane.defaultProps = {
as: Segment,
active: true,
}
+TabPane.displayName = 'TabPane'
TabPane.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
diff --git a/test/specs/modules/Tab/Tab-test.js b/test/specs/modules/Tab/Tab-test.js
index 5350952638..14bfcf1003 100644
--- a/test/specs/modules/Tab/Tab-test.js
+++ b/test/specs/modules/Tab/Tab-test.js
@@ -7,6 +7,8 @@ import { sandbox } from 'test/utils'
describe('Tab', () => {
common.isConformant(Tab)
+ common.forwardsRef(Tab)
+ common.forwardsRef(Tab, { requiredProps: { menu: { vertical: true } } })
common.hasSubcomponents(Tab, [TabPane])
const panes = [
diff --git a/test/specs/modules/Tab/TabPane-test.js b/test/specs/modules/Tab/TabPane-test.js
index 8bdb642cc6..5e69a69f68 100644
--- a/test/specs/modules/Tab/TabPane-test.js
+++ b/test/specs/modules/Tab/TabPane-test.js
@@ -5,6 +5,7 @@ import * as common from 'test/specs/commonTests'
describe('TabPane', () => {
common.isConformant(TabPane)
+ common.forwardsRef(TabPane)
common.implementsCreateMethod(TabPane)