Material-ui: Add support for chips

Created on 11 Jul 2015  路  11Comments  路  Source: mui-org/material-ui

Most helpful comment

Hey guys! I've made a Chip component for my own projects and I wanted to share it here. It's pretty ugly/sloppy but maybe someone here can use this as a good starting point. I've included a hover state because I wanted to make the close button change colour on hover (just like the material design docs).

import React from 'react';

import Avatar from 'material-ui/lib/avatar';
import CloseIcon from 'material-ui/lib/svg-icons/navigation/cancel';

export default class Chip extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      hover: false
    };
  }

  renderRemoveButton() {
    const iconStyle = {
      height: '20px',
      width: '20px',
      margin: '4px -6px 4px 4px',
      transition: 'none',
      cursor: 'pointer',
    };
    const iconColorDefault = 'rgba(0,0,0,0.3)';
    const iconColorHover = 'white';
    const iconColor = this.state.hover ? iconColorHover : iconColorDefault;
    return (
      <CloseIcon
        style={iconStyle}
        color={iconColor}
        size={20}
        onClick={this._handleClick.bind(this)}
      />
    );
  }

  _handleClick() {
    this.props.onRemoveClick.bind(this)();
  }

  _handleOnMouseEnter() {
    this.setState({hover: true});
  }

  _handleOnMouseLeave() {
    this.setState({hover: false});
  }

  render() {
    const { avatarSrc, username, noCloseButton } = this.props;
    const chipStyle = {
      height: '32px',
      lineHeight: '32px',
      padding: '0 12px',
      fontSize: '13px',
      fontWeight: '500',
      backgroundColor: this.state.hover ? '#aaa' : '#efefef',
      borderRadius: '16px',
      display: 'inline-flex',
      alignItems: 'center',
      cursor: 'default',
    };
    const avatarStyle = {
      margin: '0 8px 0 -12px',
      height: '32px',
      width: '32px',
      borderRadius: '50%',
    };

    const textStyle = {
      fontSize: '13px',
      fontWeight: '400',
      lineHeight: '16px',
      color: this.state.hover ? 'white' : 'rgba(0,0,0,0.87)',
    };
    return (
      <div
        style={chipStyle}
        onMouseEnter={this._handleOnMouseEnter.bind(this)}
        onMouseLeave={this._handleOnMouseLeave.bind(this)}
      >

        <Avatar
          src={avatarSrc}
          size={32}
          style={avatarStyle}
        />

        <span style={textStyle}>
          {username}
        </span>

        { noCloseButton ? null : this.renderRemoveButton() }

      </div>
    );
  }
}

Chip.defaultProps = {
  onRemoveClick: () => {alert(`remove ${this.props.username}`);},
  username: 'UserName',
  noCloseButton: false,
};

Here's a link to the Gist: https://gist.github.com/adrianmc/501f2fa087e96fdd816d

All 11 comments

Can https://github.com/JedWatson/react-select be wrapped to implement chips, or is it too deviated from the material specs?

has anyone started doing?

No, but PRs are always welcome! :wink:

:+1: for this!!!!! And an integration with TextField/Autocomplete would be really appreciated I think

I think I'm gonna take a stab at chips. I'm building a SaaS that has a tagging system, and either way, I'm gonna spend the hours building a tag/chip system, so I might as well do it in a way that benefits the community!

Actually this might take a long time as it's probably more complex than I'm thinking. :) For instance, chips can go into an AutoComplete field, correct? Which means that AutoComplete would have to get an overhaul to handle chips. I suppose this warrants more of a discussion here. How do you see chips working in MUI?

@ffxsam Thanks for your interest in taking a stab here! I would design the chip component as simple as possible and not worry about necessary integrating it with other components like AutoComplete yet. We can handle that separately.

I think the <Chip /> component could possibly be a stateless component that just renders consistently given props. If you have an API in mind you can write a mini proposal / code examples from end user perspective (not implementation) here and we can take a look and discuss.

Thanks!

@newoga @ffxsam Let's make chips completely decoupled from AutoComplete.

The <Chip /> component is a good start, but we should also start considering the components it will need to integrate with as they may be up for a refactor soon. The <Chip /> probably won't take too long to implement as a basic, stateless controlled component. It's adding all the state helpers that takes ages :+1:

The important thing is to make sure the basic <Chip /> supports the design in the spec and other common implementations in the simplest way possible.

I actually might wait until you guys change directions with how you style your components. Not to mention I also have zero time at the moment.. :)

Hey guys! I've made a Chip component for my own projects and I wanted to share it here. It's pretty ugly/sloppy but maybe someone here can use this as a good starting point. I've included a hover state because I wanted to make the close button change colour on hover (just like the material design docs).

import React from 'react';

import Avatar from 'material-ui/lib/avatar';
import CloseIcon from 'material-ui/lib/svg-icons/navigation/cancel';

export default class Chip extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      hover: false
    };
  }

  renderRemoveButton() {
    const iconStyle = {
      height: '20px',
      width: '20px',
      margin: '4px -6px 4px 4px',
      transition: 'none',
      cursor: 'pointer',
    };
    const iconColorDefault = 'rgba(0,0,0,0.3)';
    const iconColorHover = 'white';
    const iconColor = this.state.hover ? iconColorHover : iconColorDefault;
    return (
      <CloseIcon
        style={iconStyle}
        color={iconColor}
        size={20}
        onClick={this._handleClick.bind(this)}
      />
    );
  }

  _handleClick() {
    this.props.onRemoveClick.bind(this)();
  }

  _handleOnMouseEnter() {
    this.setState({hover: true});
  }

  _handleOnMouseLeave() {
    this.setState({hover: false});
  }

  render() {
    const { avatarSrc, username, noCloseButton } = this.props;
    const chipStyle = {
      height: '32px',
      lineHeight: '32px',
      padding: '0 12px',
      fontSize: '13px',
      fontWeight: '500',
      backgroundColor: this.state.hover ? '#aaa' : '#efefef',
      borderRadius: '16px',
      display: 'inline-flex',
      alignItems: 'center',
      cursor: 'default',
    };
    const avatarStyle = {
      margin: '0 8px 0 -12px',
      height: '32px',
      width: '32px',
      borderRadius: '50%',
    };

    const textStyle = {
      fontSize: '13px',
      fontWeight: '400',
      lineHeight: '16px',
      color: this.state.hover ? 'white' : 'rgba(0,0,0,0.87)',
    };
    return (
      <div
        style={chipStyle}
        onMouseEnter={this._handleOnMouseEnter.bind(this)}
        onMouseLeave={this._handleOnMouseLeave.bind(this)}
      >

        <Avatar
          src={avatarSrc}
          size={32}
          style={avatarStyle}
        />

        <span style={textStyle}>
          {username}
        </span>

        { noCloseButton ? null : this.renderRemoveButton() }

      </div>
    );
  }
}

Chip.defaultProps = {
  onRemoveClick: () => {alert(`remove ${this.props.username}`);},
  username: 'UserName',
  noCloseButton: false,
};

Here's a link to the Gist: https://gist.github.com/adrianmc/501f2fa087e96fdd816d

@mbrookes @oliviertassinari Awesome, nice work!

Was this page helpful?
0 / 5 - 0 ratings