Repository: react-materialize/react-materialize
Pull request #890 (2019-07-11 09:05:49)

feat: allow use of different `Icon` component
# Description

This **P.R** is to address #866 

## Type of change

- [x] New feature (non-breaking change which adds functionality)
- [x] This change requires a documentation update

# How Has This Been Tested?

Added required `spec`s

# Checklist:

- [x] I have commented my code, particularly in hard-to-understand areas
- [x] My changes generate no new warnings
- [x] I have not generated a new package version. (the maintainers will handle that)



Patch:
diff --git a/src/Autocomplete.js b/src/Autocomplete.js
index 402bcd6..e7ad3ee 100644
--- a/src/Autocomplete.js
+++ b/src/Autocomplete.js
@@ -3,7 +3,6 @@ import React, { Component } from 'react';
 import PropTypes from 'prop-types';
 import cx from 'classnames';
 import constants from './constants';
-import Icon from './Icon';
 import idgen from './idgen';
 
 class Autocomplete extends Component {
@@ -33,7 +32,7 @@ class Autocomplete extends Component {
   }
 
   renderIcon(icon) {
-    return <Icon className="prefix">{icon}</Icon>;
+    return React.cloneElement(icon, { className: 'prefix' });
   }
 
   _onChange(e) {
@@ -122,7 +121,7 @@ Autocomplete.propTypes = {
   /*
    * Optional materialize icon to add to the autocomplete bar
    */
-  icon: PropTypes.string,
+  icon: PropTypes.node,
   s: PropTypes.number,
   m: PropTypes.number,
   l: PropTypes.number,
diff --git a/src/Button.js b/src/Button.js
index c86ac91..f3c84db 100644
--- a/src/Button.js
+++ b/src/Button.js
@@ -1,14 +1,13 @@
 import React, { Component } from 'react';
+import Icon from './Icon';
 import PropTypes from 'prop-types';
 import constants from './constants';
 import cx from 'classnames';
-import Icon from './Icon';
 import idgen from './idgen';
 
 class Button extends Component {
   constructor(props) {
     super(props);
-    this.renderIcon = this.renderIcon.bind(this);
     this.renderFab = this.renderFab.bind(this);
   }
 
@@ -33,6 +32,7 @@ class Button extends Component {
 
   render() {
     const {
+      children,
       className,
       node,
       fab,
@@ -44,6 +44,7 @@ class Button extends Component {
       disabled,
       waves,
       tooltip,
+      icon,
       ...other
     } = this.props;
 
@@ -81,15 +82,15 @@ class Button extends Component {
           ref={el => (this._btnEl = el)}
           data-tooltip={tooltip}
         >
-          {this.renderIcon()}
-          {this.props.children}
+          {icon}
+          {children}
         </C>
       );
     }
   }
 
   renderFab(classes) {
-    const { fab, floating, large, className, ...other } = this.props;
+    const { fab, floating, large, className, icon, ...other } = this.props;
     return (
       <div
         {...other}
@@ -98,7 +99,7 @@ class Button extends Component {
           toolbar: fab && fab.toolbarEnabled
         })}
       >
-        <a className={classes}>{this.renderIcon()}</a>
+        <a className={classes}>{icon}</a>
         <ul>
           {React.Children.map(this.props.children, child => {
             return <li key={idgen()}>{child}</li>;
@@ -107,13 +108,6 @@ class Button extends Component {
       </div>
     );
   }
-
-  renderIcon() {
-    const { icon } = this.props;
-    if (!icon) return;
-
-    return <Icon>{icon}</Icon>;
-  }
 }
 
 Button.propTypes = {
@@ -149,7 +143,7 @@ Button.propTypes = {
   /**
    * The icon to display, if specified it will create a button with the material icon.
    */
-  icon: PropTypes.string,
+  icon: PropTypes.node,
   modal: PropTypes.oneOf(['close', 'confirm']),
   node: PropTypes.node,
   /**
@@ -182,7 +176,8 @@ Button.propTypes = {
 };
 
 Button.defaultProps = {
-  node: 'button'
+  node: 'button',
+  icon: <Icon>edit</Icon>
 };
 
 export default Button;
diff --git a/src/Card.js b/src/Card.js
index 2fff457..eb71126 100644
--- a/src/Card.js
+++ b/src/Card.js
@@ -1,4 +1,4 @@
-import React, { Component } from 'react';
+import React, { Component, Fragment, cloneElement } from 'react';
 import PropTypes from 'prop-types';
 import cx from 'classnames';
 import Icon from './Icon';
@@ -14,6 +14,8 @@ class Card extends Component {
   }
 
   renderTitle(title, reveal) {
+    const { revealIcon } = this.props;
+
     return (
       <span
         className={cx('card-title', {
@@ -21,17 +23,19 @@ class Card extends Component {
         })}
       >
         {title}
-        {reveal && <Icon right>more_vert</Icon>}
+        {reveal && { revealIcon }}
       </span>
     );
   }
 
   renderReveal(title, reveal) {
+    const { closeIcon } = this.props;
+
     return (
       <div className="card-reveal">
         <span className="card-title">
           {title}
-          <Icon right>close</Icon>
+          {cloneElement(closeIcon, { right: true })}
         </span>
         {reveal}
       </div>
@@ -53,11 +57,11 @@ class Card extends Component {
 
   renderAll(title, reveal, textClassName, children, actions) {
     return (
-      <React.Fragment>
+      <Fragment>
         {this.renderContent(title, reveal, textClassName, children)}
         {this.renderReveal(title, reveal)}
         {actions && this.renderAction(actions)}
-      </React.Fragment>
+      </Fragment>
     );
   }
 
@@ -103,7 +107,14 @@ Card.propTypes = {
   header: PropTypes.element,
   // The buttons to be displayed at the action area
   actions: PropTypes.arrayOf(PropTypes.element),
-  horizontal: PropTypes.bool
+  horizontal: PropTypes.bool,
+  closeIcon: PropTypes.node,
+  revealIcon: PropTypes.node
+};
+
+Card.defaultProps = {
+  closeIcon: <Icon>close</Icon>,
+  revealIcon: <Icon>more_vert</Icon>
 };
 
 export default Card;
diff --git a/src/Chip.js b/src/Chip.js
index 1182839..46421a1 100644
--- a/src/Chip.js
+++ b/src/Chip.js
@@ -1,4 +1,4 @@
-import React, { Component } from 'react';
+import React, { Fragment, Component } from 'react';
 import PropTypes from 'prop-types';
 import cx from 'classnames';
 import Icon from './Icon';
@@ -17,7 +17,14 @@ class Chip extends Component {
   }
 
   render() {
-    const { children, close, className, options, ...other } = this.props;
+    const {
+      children,
+      close,
+      closeIcon,
+      className,
+      options,
+      ...other
+    } = this.props;
 
     const classes = cx(
       {
@@ -27,10 +34,10 @@ class Chip extends Component {
       className
     );
     let chipContent = (
-      <React.Fragment>
+      <Fragment>
         {children}
-        {close && <Icon className="close">close</Icon>}
-      </React.Fragment>
+        {close && { closeIcon }}
+      </Fragment>
     );
 
     if (options) {
@@ -58,6 +65,7 @@ Chip.propTypes = {
    * Shows a close icon
    */
   close: PropTypes.bool,
+  closeIcon: PropTypes.node,
   /**
    * Options object for the Chip Javascript Plugin
    */
@@ -112,6 +120,7 @@ Chip.propTypes = {
 
 Chip.defaultProps = {
   close: false,
+  closeIcon: <Icon>close</Icon>,
   options: null
 };
 
diff --git a/src/CollapsibleItem.js b/src/CollapsibleItem.js
index cd63983..cf04736 100644
--- a/src/CollapsibleItem.js
+++ b/src/CollapsibleItem.js
@@ -1,7 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import cx from 'classnames';
-import Icon from './Icon';
 
 const CollapsibleItem = ({
   className,
@@ -20,7 +19,7 @@ const CollapsibleItem = ({
       className={cx('collapsible-header', { active: expanded })}
       onClick={() => onSelect(eventKey)}
     >
-      {icon && <Icon className={iconClassName}>{icon}</Icon>}
+      {icon}
       {header}
     </Node>
     <div className="collapsible-body">{children}</div>
@@ -29,7 +28,7 @@ const CollapsibleItem = ({
 
 CollapsibleItem.propTypes = {
   header: PropTypes.any.isRequired,
-  icon: PropTypes.string,
+  icon: PropTypes.node,
   iconClassName: PropTypes.string,
   children: PropTypes.node,
   onSelect: PropTypes.func,
diff --git a/src/Navbar.js b/src/Navbar.js
index c5a3083..6909bba 100644
--- a/src/Navbar.js
+++ b/src/Navbar.js
@@ -2,7 +2,7 @@ import React, { Component, Fragment, Children } from 'react';
 import PropTypes from 'prop-types';
 import cx from 'classnames';
 import Icon from './Icon';
-import TextInput from './TextInput';
+import SearchForm from './SearchForm';
 
 class Navbar extends Component {
   componentDidMount() {
@@ -29,6 +29,7 @@ class Navbar extends Component {
       alignLinks,
       centerLogo,
       search,
+      menuIcon,
       sidenav
     } = this.props;
 
@@ -62,11 +63,7 @@ class Navbar extends Component {
       <nav className={navCSS}>
         <div className="nav-wrapper">
           {search ? (
-            <form>
-              <TextInput label={<Icon>search</Icon>} type="search">
-                <Icon>close</Icon>
-              </TextInput>
-            </form>
+            <SearchForm />
           ) : (
             <Fragment>
               {brand &&
@@ -74,7 +71,7 @@ class Navbar extends Component {
                   className: cx(brand.props.className, brandClasses)
                 })}
               <a href="#!" data-target="mobile-nav" className="sidenav-trigger">
-                <Icon>menu</Icon>
+                {menuIcon}
               </a>
               <ul className={navMobileCSS}>{links}</ul>
             </Fragment>
@@ -152,7 +149,8 @@ Navbar.propTypes = {
     onCloseEnd: PropTypes.func,
     // Prevent page from scrolling while sidenav is open.
     preventScrolling: PropTypes.bool
-  })
+  }),
+  menuIcon: PropTypes.node.isRequired
 };
 
 Navbar.defaultProps = {
@@ -166,7 +164,8 @@ Navbar.defaultProps = {
     onCloseStart: null,
     onCloseEnd: null,
     preventScrolling: true
-  }
+  },
+  menuIcon: <Icon>menu</Icon>
 };
 
 export default Navbar;
diff --git a/src/Pagination.js b/src/Pagination.js
index 35dd277..d35e45a 100644
--- a/src/Pagination.js
+++ b/src/Pagination.js
@@ -37,7 +37,13 @@ class Pagination extends Component {
   }
 
   renderButtons() {
-    const { items, children, maxButtons = items } = this.props;
+    const {
+      items,
+      children,
+      maxButtons = items,
+      leftBtn,
+      rightBtn
+    } = this.props;
     const { activePage } = this.state;
 
     if (children) return children;
@@ -61,7 +67,7 @@ class Pagination extends Component {
         key={'pagination-0'}
         onSelect={this._onClick(activePage - 1)}
       >
-        <Icon>chevron_left</Icon>
+        {leftBtn}
       </PaginationButton>
     ];
 
@@ -83,7 +89,7 @@ class Pagination extends Component {
         disabled={activePage === items}
         onSelect={this._onClick(activePage + 1)}
       >
-        <Icon>chevron_right</Icon>
+        {rightBtn}
       </PaginationButton>
     );
 
@@ -111,12 +117,16 @@ Pagination.propTypes = {
   children: PropTypes.node,
   className: PropTypes.string,
   maxButtons: PropTypes.number,
-  onSelect: PropTypes.func
+  onSelect: PropTypes.func,
+  leftBtn: PropTypes.node,
+  rightBtn: PropTypes.node
 };
 
 Pagination.defaultProps = {
   activePage: 1,
-  items: 10
+  items: 10,
+  leftBtn: <Icon>chevron_left</Icon>,
+  rightBtn: <Icon>chevron_right</Icon>
 };
 
 export default Pagination;
diff --git a/src/SearchForm.js b/src/SearchForm.js
index a89af41..5a63328 100644
--- a/src/SearchForm.js
+++ b/src/SearchForm.js
@@ -1,16 +1,24 @@
 import React from 'react';
+import PropTypes from 'prop-types';
 import Icon from './Icon';
+import TextInput from './TextInput';
 
-const SearchForm = () => (
+const SearchForm = ({ searchIcon, closeIcon }) => (
   <form>
-    <div className="input-field">
-      <input id="search" type="search" required />
-      <label className="label-icon" htmlFor="search">
-        <Icon>search</Icon>
-      </label>
-      <Icon>close</Icon>
-    </div>
+    <TextInput label={searchIcon} type="search">
+      {closeIcon}
+    </TextInput>
   </form>
 );
 
+SearchForm.propTypes = {
+  searchIcon: PropTypes.node.isRequired,
+  closeIcon: PropTypes.node.isRequired
+};
+
+SearchForm.defaultProps = {
+  searchIcon: <Icon>search</Icon>,
+  closeIcon: <Icon>close</Icon>
+};
+
 export default SearchForm;
diff --git a/src/Select.js b/src/Select.js
index 8e852f7..1151a1e 100644
--- a/src/Select.js
+++ b/src/Select.js
@@ -1,7 +1,6 @@
 import React, { Component, Children, cloneElement } from 'react';
 import PropTypes from 'prop-types';
 import cx from 'classnames';
-import Icon from './Icon';
 import idgen from './idgen';
 import constants from './constants';
 
@@ -103,7 +102,8 @@ class Select extends Component {
         </label>
       );
 
-    const renderIcon = () => icon && <Icon className="prefix">{icon}</Icon>;
+    const renderIcon = () =>
+      icon && React.cloneElement(icon, { className: 'prefix' });
 
     const renderOption = child =>
       cloneElement(child, { key: child.props.value });
@@ -174,7 +174,7 @@ Select.propTypes = {
   /*
    * prefix icon
    */
-  icon: PropTypes.string,
+  icon: PropTypes.node,
   /*
    * label text
    */
diff --git a/src/SideNavItem.js b/src/SideNavItem.js
index 0567831..985dab7 100644
--- a/src/SideNavItem.js
+++ b/src/SideNavItem.js
@@ -45,7 +45,7 @@ SideNavItem.propTypes = {
   userView: PropTypes.bool,
   waves: PropTypes.bool,
   href: PropTypes.string,
-  icon: PropTypes.string,
+  icon: PropTypes.node,
   user: PropTypes.shape(UserShape)
 };
 
diff --git a/src/TextInput.js b/src/TextInput.js
index 9ac57d3..ef4214d 100644
--- a/src/TextInput.js
+++ b/src/TextInput.js
@@ -181,7 +181,7 @@ TextInput.propTypes = {
   /*
    * prefix icon, name of the icon or a node
    */
-  icon: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
+  icon: PropTypes.node,
   /*
    * label text
    */
diff --git a/src/Textarea.js b/src/Textarea.js
index a5eebf7..21ad838 100644
--- a/src/Textarea.js
+++ b/src/Textarea.js
@@ -2,7 +2,6 @@ import React, { Component } from 'react';
 import PropTypes from 'prop-types';
 import cx from 'classnames';
 import idgen from './idgen';
-import Icon from './Icon';
 import constants from './constants';
 
 class Textarea extends Component {
@@ -98,10 +97,6 @@ class Textarea extends Component {
     const renderIcon = () => {
       if (!icon) return;
 
-      if (typeof icon === 'string') {
-        return <Icon className="prefix">{icon}</Icon>;
-      }
-
       return React.cloneElement(icon, { className: 'prefix' });
     };
 
@@ -162,7 +157,7 @@ Textarea.propTypes = {
   /*
    * render icon next to input
    */
-  icon: PropTypes.string,
+  icon: PropTypes.node,
   /*
    * icon classname
    */
diff --git a/stories/Autocomplete.stories.js b/stories/Autocomplete.stories.js
index 1f2c037..f7ff10a 100644
--- a/stories/Autocomplete.stories.js
+++ b/stories/Autocomplete.stories.js
@@ -1,6 +1,7 @@
 import React from 'react';
 import { storiesOf } from '@storybook/react';
 import Autocomplete from '../src/Autocomplete';
+import Icon from '../src/Icon';
 import { text, withKnobs } from '@storybook/addon-knobs';
 
 const stories = storiesOf('Javascript|Autocomplete', module);
@@ -39,7 +40,7 @@ stories.add(
         }
       }}
       placeholder="Insert here"
-      icon={text('icon', 'textsms')}
+      icon={<Icon>{text('icon', 'textsms')}</Icon>}
     />
   ),
   { notes }
diff --git a/stories/Button.stories.js b/stories/Button.stories.js
index 606fe2d..c5d7951 100644
--- a/stories/Button.stories.js
+++ b/stories/Button.stories.js
@@ -28,7 +28,13 @@ stories.add('Default', () => (
 ));
 
 stories.add('Floating', () => (
-  <Button floating large className="red" waves="light" icon="add" />
+  <Button
+    floating
+    large
+    className="red"
+    waves="light"
+    icon={<Icon>add</Icon>}
+  />
 ));
 
 stories.add('Flat', () => (
@@ -115,7 +121,7 @@ stories.add('Waves', () => (
         ['light', 'red', 'yellow', 'orange', 'purple', 'green', 'teal'],
         'light'
       )}
-      icon="add"
+      icon={<Icon>add</Icon>}
     />
   </div>
 ));
@@ -173,15 +179,19 @@ stories.add('Tooltip', () => {
 
 const storiesFab = storiesOf('Components|FAB', module);
 const children = [
-  <Button key="1" floating icon="insert_chart" className="red" />,
-  <Button key="2" floating icon="format_quote" className="yellow darken-1" />,
-  <Button key="3" floating icon="publish" className="green" />,
-  <Button key="4" floating icon="attach_file" className="blue" />
+  <Button key="1" floating icon={<Icon>insert_chart</Icon>} className="red" />,
+  <Button
+    key="2"
+    floating
+    icon={<Icon>format_quote</Icon>}
+    className="yellow darken-1"
+  />,
+  <Button key="3" floating icon={<Icon>publish</Icon>} className="green" />,
+  <Button key="4" floating icon={<Icon>attach_file</Icon>} className="blue" />
 ];
 const props = {
   floating: true,
   fab: true,
-  icon: 'edit',
   className: 'red',
   large: true
 };
@@ -214,6 +224,6 @@ storiesFab.add('Click-only', () => (
 
 storiesFab.add('To toolbar', () => (
   <Button {...props} fab={{ direction: 'top', toolbarEnabled: true }}>
-    {children}
+    {children.map(c => React.cloneElement(c, { className: 'btn-large red' }))}
   </Button>
 ));
diff --git a/stories/Collapsible.stories.js b/stories/Collapsible.stories.js
index 133adcd..f83c127 100644
--- a/stories/Collapsible.stories.js
+++ b/stories/Collapsible.stories.js
@@ -2,6 +2,7 @@ import React from 'react';
 import { storiesOf } from '@storybook/react';
 import Collapsible from '../src/Collapsible';
 import CollapsibleItem from '../src/CollapsibleItem';
+import Icon from '../src/Icon';
 
 const stories = storiesOf('Javascript|Collapsible', module);
 
@@ -18,19 +19,19 @@ stories.add('Accordion', () => (
   <Collapsible>
     <CollapsibleItem
       header="Better safe than sorry. That's my motto."
-      icon="filter_drama"
+      icon={<Icon>filter_drama</Icon>}
     >
       Better safe than sorry. That's my motto.
     </CollapsibleItem>
     <CollapsibleItem
       header="Yeah, you do seem to have a little 'shit creek' action going."
-      icon="place"
+      icon={<Icon>place</Icon>}
     >
       Yeah, you do seem to have a little 'shit creek' action going.
     </CollapsibleItem>
     <CollapsibleItem
       header="You know, FYI, you can buy a paddle. Did you not plan for this contingency?"
-      icon="whatshot"
+      icon={<Icon>whatshot</Icon>}
     >
       You know, FYI, you can buy a paddle. Did you not plan for this
       contingency?
@@ -42,19 +43,19 @@ stories.add('Expandable', () => (
   <Collapsible accordion={false}>
     <CollapsibleItem
       header="Better safe than sorry. That's my motto."
-      icon="filter_drama"
+      icon={<Icon>filter_drama</Icon>}
     >
       Better safe than sorry. That's my motto.
     </CollapsibleItem>
     <CollapsibleItem
       header="Yeah, you do seem to have a little 'shit creek' action going."
-      icon="place"
+      icon={<Icon>place</Icon>}
     >
       Yeah, you do seem to have a little 'shit creek' action going.
     </CollapsibleItem>
     <CollapsibleItem
       header="You know, FYI, you can buy a paddle. Did you not plan for this contingency?"
-      icon="whatshot"
+      icon={<Icon>whatshot</Icon>}
     >
       You know, FYI, you can buy a paddle. Did you not plan for this
       contingency?
@@ -66,19 +67,19 @@ stories.add('Popout', () => (
   <Collapsible popout>
     <CollapsibleItem
       header="Better safe than sorry. That's my motto."
-      icon="filter_drama"
+      icon={<Icon>filter_drama</Icon>}
     >
       Better safe than sorry. That's my motto.
     </CollapsibleItem>
     <CollapsibleItem
       header="Yeah, you do seem to have a little 'shit creek' action going."
-      icon="place"
+      icon={<Icon>place</Icon>}
     >
       Yeah, you do seem to have a little 'shit creek' action going.
     </CollapsibleItem>
     <CollapsibleItem
       header="You know, FYI, you can buy a paddle. Did you not plan for this contingency?"
-      icon="whatshot"
+      icon={<Icon>whatshot</Icon>}
     >
       You know, FYI, you can buy a paddle. Did you not plan for this
       contingency?
@@ -90,20 +91,20 @@ stories.add('Preselected Section', () => (
   <Collapsible>
     <CollapsibleItem
       header="Better safe than sorry. That's my motto."
-      icon="filter_drama"
+      icon={<Icon>filter_drama</Icon>}
     >
       Better safe than sorry. That's my motto.
     </CollapsibleItem>
     <CollapsibleItem
       header="Yeah, you do seem to have a little 'shit creek' action going."
-      icon="place"
+      icon={<Icon>place</Icon>}
       expanded
     >
       Yeah, you do seem to have a little 'shit creek' action going.
     </CollapsibleItem>
     <CollapsibleItem
       header="You know, FYI, you can buy a paddle. Did you not plan for this contingency?"
-      icon="whatshot"
+      icon={<Icon>whatshot</Icon>}
     >
       You know, FYI, you can buy a paddle. Did you not plan for this
       contingency?


Test patch:
diff --git a/test/Chip.spec.js b/test/Chip.spec.js
index ef69559..e1348a8 100644
--- a/test/Chip.spec.js
+++ b/test/Chip.spec.js
@@ -14,8 +14,7 @@ describe('<Chip />', () => {
 
   test('accepts a close prop', () => {
     wrapper = shallow(<Chip close />);
-    expect(wrapper.find(Icon).prop('className')).toBe('close');
-    expect(wrapper.find(Icon)).toHaveLength(1);
+    expect(wrapper.find(<Icon>close</Icon>)).toBeTruthy();
   });
 
   test('accepts children', () => {
diff --git a/test/__snapshots__/Button.spec.js.snap b/test/__snapshots__/Button.spec.js.snap
index 27a58bd..ee86ea2 100644
--- a/test/__snapshots__/Button.spec.js.snap
+++ b/test/__snapshots__/Button.spec.js.snap
@@ -5,6 +5,9 @@ exports[`Button renders 1`] = `
   className="btn waves-effect waves-light"
   disabled={false}
 >
+  <Icon>
+    edit
+  </Icon>
   Stuff
 </button>
 `;
diff --git a/test/__snapshots__/Card.spec.js.snap b/test/__snapshots__/Card.spec.js.snap
index ff42c68..2f331e3 100644
--- a/test/__snapshots__/Card.spec.js.snap
+++ b/test/__snapshots__/Card.spec.js.snap
@@ -3,6 +3,16 @@
 exports[`<Card /> renders 1`] = `
 <div
   className="blue-grey darken-1 card"
+  closeIcon={
+    <Icon>
+      close
+    </Icon>
+  }
+  revealIcon={
+    <Icon>
+      more_vert
+    </Icon>
+  }
 >
   <div
     className="card-content white-text"
diff --git a/test/__snapshots__/Chip.spec.js.snap b/test/__snapshots__/Chip.spec.js.snap
index f7f1d55..8e10aed 100644
--- a/test/__snapshots__/Chip.spec.js.snap
+++ b/test/__snapshots__/Chip.spec.js.snap
@@ -9,11 +9,7 @@ exports[`<Chip /> accepts children 1`] = `
   >
     Child
   </p>
-  <Icon
-    className="close"
-  >
-    close
-  </Icon>
+  <Component />
 </div>
 `;
 
diff --git a/test/__snapshots__/Modal.spec.js.snap b/test/__snapshots__/Modal.spec.js.snap
index f8761d3..f80d610 100644
--- a/test/__snapshots__/Modal.spec.js.snap
+++ b/test/__snapshots__/Modal.spec.js.snap
@@ -6,6 +6,11 @@ exports[`<Modal /> renders a modal has children 1`] = `
     Array [
       <Button
         flat={true}
+        icon={
+          <Icon>
+            edit
+          </Icon>
+        }
         modal="close"
         node="button"
         waves="green"
@@ -60,6 +65,11 @@ exports[`<Modal /> renders a modal has children 1`] = `
             <button
               class="waves-effect waves-green btn-flat modal-close"
             >
+              <i
+                class="material-icons"
+              >
+                edit
+              </i>
               Close
             </button>
           </div>
@@ -88,6 +98,11 @@ exports[`<Modal /> renders a modal has children 1`] = `
       >
         <Button
           flat={true}
+          icon={
+            <Icon>
+              edit
+            </Icon>
+          }
           key=".0"
           modal="close"
           node="button"
@@ -97,6 +112,13 @@ exports[`<Modal /> renders a modal has children 1`] = `
             className="waves-effect waves-green btn-flat modal-close"
             disabled={false}
           >
+            <Icon>
+              <i
+                className="material-icons"
+              >
+                edit
+              </i>
+            </Icon>
             Close
           </button>
         </Button>
@@ -112,6 +134,11 @@ exports[`<Modal /> renders a trigger renders 1`] = `
     Array [
       <Button
         flat={true}
+        icon={
+          <Icon>
+            edit
+          </Icon>
+        }
         modal="close"
         node="button"
         waves="green"
@@ -166,6 +193,11 @@ exports[`<Modal /> renders a trigger renders 1`] = `
             <button
               class="waves-effect waves-green btn-flat modal-close"
             >
+              <i
+                class="material-icons"
+              >
+                edit
+              </i>
               Close
             </button>
           </div>
@@ -194,6 +226,11 @@ exports[`<Modal /> renders a trigger renders 1`] = `
       >
         <Button
           flat={true}
+          icon={
+            <Icon>
+              edit
+            </Icon>
+          }
           key=".0"
           modal="close"
           node="button"
@@ -203,6 +240,13 @@ exports[`<Modal /> renders a trigger renders 1`] = `
             className="waves-effect waves-green btn-flat modal-close"
             disabled={false}
           >
+            <Icon>
+              <i
+                className="material-icons"
+              >
+                edit
+              </i>
+            </Icon>
             Close
           </button>
         </Button>
@@ -218,6 +262,11 @@ exports[`<Modal /> without a trigger renders 1`] = `
     Array [
       <Button
         flat={true}
+        icon={
+          <Icon>
+            edit
+          </Icon>
+        }
         modal="close"
         node="button"
         waves="green"
@@ -259,6 +308,11 @@ exports[`<Modal /> without a trigger renders 1`] = `
             <button
               class="waves-effect waves-green btn-flat modal-close"
             >
+              <i
+                class="material-icons"
+              >
+                edit
+              </i>
               Close
             </button>
           </div>
@@ -285,6 +339,11 @@ exports[`<Modal /> without a trigger renders 1`] = `
       >
         <Button
           flat={true}
+          icon={
+            <Icon>
+              edit
+            </Icon>
+          }
           key=".0"
           modal="close"
           node="button"
@@ -294,6 +353,13 @@ exports[`<Modal /> without a trigger renders 1`] = `
             className="waves-effect waves-green btn-flat modal-close"
             disabled={false}
           >
+            <Icon>
+              <i
+                className="material-icons"
+              >
+                edit
+              </i>
+            </Icon>
             Close
           </button>
         </Button>
diff --git a/test/__snapshots__/Navbar.spec.js.snap b/test/__snapshots__/Navbar.spec.js.snap
index 60aedb0..5f814e0 100644
--- a/test/__snapshots__/Navbar.spec.js.snap
+++ b/test/__snapshots__/Navbar.spec.js.snap
@@ -9,6 +9,11 @@ exports[`<Navbar /> adds a brand node 1`] = `
       I AM BRAND
     </span>
   }
+  menuIcon={
+    <Icon>
+      menu
+    </Icon>
+  }
   options={
     Object {
       "draggable": true,
@@ -213,7 +218,13 @@ exports[`<Navbar /> can have custom sidenav 1`] = `
   <ul
     className="sidenav left"
     id="mobile-nav"
-  />
+  >
+    <li
+      className="custom-node"
+    >
+      Custom node!
+    </li>
+  </ul>
 </Fragment>
 `;
 
@@ -431,4 +442,4 @@ exports[`<Navbar /> can have children with custom ids 1`] = `
     </li>
   </ul>
 </Fragment>
-`;
\ No newline at end of file
+`;
diff --git a/test/__snapshots__/SearchForm.spec.js.snap b/test/__snapshots__/SearchForm.spec.js.snap
index 6dc73d2..4085cbd 100644
--- a/test/__snapshots__/SearchForm.spec.js.snap
+++ b/test/__snapshots__/SearchForm.spec.js.snap
@@ -2,25 +2,17 @@
 
 exports[`<SearchForm /> should render 1`] = `
 <form>
-  <div
-    className="input-field"
-  >
-    <input
-      id="search"
-      required={true}
-      type="search"
-    />
-    <label
-      className="label-icon"
-      htmlFor="search"
-    >
+  <TextInput
+    label={
       <Icon>
         search
       </Icon>
-    </label>
+    }
+    type="search"
+  >
     <Icon>
       close
     </Icon>
-  </div>
+  </TextInput>
 </form>
 `;
diff --git a/test/__snapshots__/Select.spec.js.snap b/test/__snapshots__/Select.spec.js.snap
index e838cc2..8a8cb73 100644
--- a/test/__snapshots__/Select.spec.js.snap
+++ b/test/__snapshots__/Select.spec.js.snap
@@ -4,11 +4,9 @@ exports[`<Select /> with icon 1`] = `
 <div
   className="input-field col"
 >
-  <Icon
+  <Component
     className="prefix"
-  >
-    cloud
-  </Icon>
+  />
   <select
     className=""
     id="mockId"
diff --git a/test/__snapshots__/Textarea.spec.js.snap b/test/__snapshots__/Textarea.spec.js.snap
index d1a0d30..5e8b02e 100644
--- a/test/__snapshots__/Textarea.spec.js.snap
+++ b/test/__snapshots__/Textarea.spec.js.snap
@@ -20,11 +20,9 @@ exports[`<Textarea /> Icon 1`] = `
 <div
   className="input-field col"
 >
-  <Icon
+  <Component
     className="prefix"
-  >
-    mode_edit
-  </Icon>
+  />
   <textarea
     className="materialize-textarea"
     id="mockId"
diff --git a/test/__snapshots__/Toast.spec.js.snap b/test/__snapshots__/Toast.spec.js.snap
index 02b7711..84683aa 100644
--- a/test/__snapshots__/Toast.spec.js.snap
+++ b/test/__snapshots__/Toast.spec.js.snap
@@ -3,6 +3,11 @@
 exports[`Toast renders 1`] = `
 <Button
   className="toast"
+  icon={
+    <Icon>
+      edit
+    </Icon>
+  }
   node="button"
   onClick={[Function]}
 >