Material-ui: Tabs Children Validation Error

Created on 7 Mar 2016  路  13Comments  路  Source: mui-org/material-ui

Problem Description

I realize there is validation to check whether a Tab component is the direct child: https://github.com/callemall/material-ui/blob/master/src/tabs/tabs.jsx#L215

How do I avoid this error if I want to wrap the Material UI Tab component with my own custom Tab component?

Warning: Tabs only accepts Tab Components as children.
        Found function Tab(props) {
        _classCallCheck(this, Tab);

        var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(Tab).call(this, props));

        _this.displayName = 'Tab';
        return _this;
      } as child number 1 of Tabs

My component logic:

export default class Tab extends React.Component {
  constructor(props){
    super(props);
    this.displayName = 'Tab';
  }

  render(){

    return (
      <MUITab 
        {...this.props} 
        className={classNames(
          'tab',
          { 'selected': this.props.selected },
          this.props.className
        )}
        style={style} 
      />
    );
  }
}

Versions

  • Material-UI: 0.14.4
  • React: 0.14.7
  • Browser: Chrome latest

Most helpful comment

I just ran across this as well.

For reference, the property that Tabs validates on its children changed from displayName to muiName at some point between then and now.

The following example works as of 0.15.1:

// CustomTab.jsx
import { Tab as MuiTab } from 'material-ui/Tabs';

const Tab = (props) => (<MuiTab {...props} />);
Tab.muiName = 'Tab';

export default Tab;

All 13 comments

Thanks for your response, @Aweary. I'm not sure how to access the type. I tried this.displayName in the constructor, but that didn't work. Did you mean something like this?

Tab.type = {
  displayName: 'Tab'
};

Edit: I was able to figure it out!

All I had to do was write the following:

Tab.displayName = 'Tab';

I'm not sure why this.displayName didn't work.

@ConAntonakos glad to hear it! I deleted my response because I wasn't 100% sure it was accurate, but I'm glad it helped :+1: :tada:

I'm not sure why this.displayName didn't work.

because displayName should be a static property not instance member. I would advise against this approach. But it's the best workaround for now. The better solution would have been making Tabs component customizable enough for these use-cases. So if you want to harden this please open a PR, but if the workaround works out for you then I'm glag your issue was resolved :+1: :smile:

I have this problem too within reagent and can't use the above displayName trick. How can I make the parent Tabs component accept a custom Tab class of mine?

(defn tab []
  (reagent/create-class
    {:display-name        "Tab"
     :reagent-render      (fn [props & children]
                            [rui/tab (merge props {:style {:padding-top tab-padding-top}})
                             (map-keys children)])}))

gives material-ui.inc.js:24946 Warning: Tabs only accepts Tab Components as children.

I just ran across this as well.

For reference, the property that Tabs validates on its children changed from displayName to muiName at some point between then and now.

The following example works as of 0.15.1:

// CustomTab.jsx
import { Tab as MuiTab } from 'material-ui/Tabs';

const Tab = (props) => (<MuiTab {...props} />);
Tab.muiName = 'Tab';

export default Tab;

Ran across this after upgrading from 14 to 15. My solution after seeing @FaideWW's comment is to do this outside the class:
Foo.muiName = 'Tab';

If you have the proper babel setup, you can use static properties on the class.

class Foo extends Component {
    static muiName = 'Tab';

Really just depends on your specific set-up and your standards.

Luckily, this was an easy fix. For those of us who wrap components to generalize/standardize them for use throughout an app, this tiptoes the line of being really bad. If there were not an easy way to fix this warning, I would propose removing it. There is an easy fix, so it seems to be okay to keep.

I guess it depends on opinion, but many are of the opinion that a library for components should not enforce usage in such a way. It should always allow for the flexibility of wrapping components and doing what needs to be done to write composable components. I'm in this camp.

Just ran into this issue again. Contents of my custom tabs won't show. I hope this is on the docket to be fixed in next.

I am also having this issue. I can add static muiName = "Tab" or CustomTab.muiName = "Tab" which gets rid of the warning, but the tab still doesn't render as expected.

My use case is I want to encapsulate my tab logic/template into its own component. Like everyone else in this issue, all I do is return a muiTab that has all the content and logic. Not sure why this is a problem.

Any idea on a potential fix?

Currently this is the only way I can achieve what I want. It's not ideal, but I guess it will have to do. Why is this important? It allows for reusable tabs in different tab groups. I may have 3 different pages that have tab groups, all 3 use custom tab 1 and 2 use custom tab 2.

```javascript
// ./custom-tab-1.js

export default () => {
return (

Custom Tab 1

);
};

// ./custom-tab-2.js
export default () => {
return (

Custom Tab 2

);
};

// ./page.js

import CustomTab1 from "./custom-tab-1";
import CustomTab2 from "./custom-tab-2";

export default () => {
return (

{/* The tab should be able to be inside custom tab 1 instead of a dummy

wrapper */}






);
}

At the current time is there any other solution any other than @blackdynamo suggested ?
Even with

class Foo extends Component {
    static muiName = 'Tab';

I get rid of the warning but the CSS seem to be messed up 馃槓

@heron182 The Tabs component passes props to the Tab component. Are you passing on the props?

import React from 'react';
import { Tab as MaterialTab } from 'material-ui/Tabs'; 

class Tab extends React.PureComponent {
  getPropsPassedFromParent() {
    return {
      index: this.props.index,
      onClick: this.props.onClick,
      selected: this.props.selected,
      width: this.props.width,
    }
  }

  render() {
    return (
      <MaterialTab 
        {...this.getPropsPassedFromParent()}
        label={this.props.label}
        style={{ textTransform: 'none' }}
      />
    );
  }
}

// https://github.com/mui-org/material-ui/issues/3622#issuecomment-227877809
Tab.displayName = Tab.muiName = 'Tab';

export default Tab;

@BenLorantfy TBH I moved along with @blackdynamo's solution and currently am working in other project. Will keep your solution around and if i come up with a "tab" problem again, I'll let you know. Thanks !

Thanks @BenLorantfy! I was having this issue, and it was because I wasn't spreading the all props; I was just using the ones that I was explicitly passing myself. It is not very intuitive that Tabs manipulates its children's props.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

FranBran picture FranBran  路  3Comments

reflog picture reflog  路  3Comments

activatedgeek picture activatedgeek  路  3Comments

chris-hinds picture chris-hinds  路  3Comments

mb-copart picture mb-copart  路  3Comments