Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I dynamically load an icon using its snake_case name (React, material-ui)

Normally I'd use material-ui icons by importing them directly per the material-ui instructions.

But I have a text tag, which is the actual icon name (like calendar_view_day) and need to get and render an icon component from it dynamically.

How can I something like:

render() {
  return (
    <Icon name="calendar_view_day" color="primary" />
  )
}

Instead of:

render() {
  return (
    <CalendarViewDay color="primary" />  // Imported by name
  )
}
like image 977
thclark Avatar asked May 29 '19 22:05

thclark


People also ask

How do I use material icons in material UI?

If you don't use Material UI in your project yet, install the icons package with npm install @mui/icons-material @mui/material @emotion/styled @emotion/react . See the Installation page for additional docs about how to make sure everything is set up correctly.

How do I add an icon to a material UI button in React?

Create an icon buttonImport the IconButton component from the Material-UI core package. import IconButton from '@material-ui/core/IconButton'; Render the icon as a child component to the IconButton . You can also move the color prop to the IconButton .


1 Answers

OK, so I massively overthought this.

Correct answer

Turns out material-ui includes an icon component that allows you to do this... and it converts names itself, so accepts snake, pascal and other variants. BEWARE this will massively increase bundle size, as pointed out in the comments. If you're bundle size constrained, you'll have to take a different approach of serving the icon SVGs from somewhere!

import Icon from '@material-ui/core/Icon'

...

render() {
  return (
    <Icon>{props.iconName}</Icon>
  )
}

Previous answer (working but massive overkill)

Create function to:

  • convert snake_case to PascalCase
  • Handle special cases reported in the material-ui icons documentation

...Then use the material-ui Icon component.

Here's the code:

import Icon from '@material-ui/core/Icon'

function upperFirst(string) {
  return string.slice(0, 1).toUpperCase() + string.slice(1, string.length)
}

function fixIconNames(string) {
  const name = string.split('_').map(upperFirst).join('')
  if (name === '3dRotation') {
    return 'ThreeDRotation'
  } else if (name === '4k') {
    return 'FourK'
  } else if (name === '360') {
    return 'ThreeSixty'
  }
  return name
}

...

render() {
  const iconName = fixIconNames(props.iconName)
  return (
    <Icon>{props.iconName}</Icon>
  )
}
like image 114
thclark Avatar answered Nov 28 '22 08:11

thclark