Creating a button in ReactJS with text displayed under an icon

Presently, I am working with a component that looks like this: https://i.stack.imgur.com/qGCwj.png

This is the code for the component:

import React from "react";
import {withStyles} from "material-ui/styles";
import Settings from "material-ui-icons/Settings"; 
import Button from "material-ui/Button";

const styles = {
button: {
    color: "primary",
    height: 95,
    width: 95,
    disableRipple: "true",
    focusRipple: "true",
},
icon: {
    height: 35,
    width: 35,
    display: "block",
    float: "none",
},
text: {
    height: 35,
    width: 35,
    display: "block",
    float: "none",
    marginTop: 10,
},
};

/* eslint-disable react/prop-types */
const IconedLabel = ({classes}) => (
<section>
    <Button className={classes.iconButton} variant="raised" color="primary">
        <Settings className={classes.icon}/>
        <div className={classes.text}>Message</div>
    </Button>
</section>
);

export default withStyles(styles)(IconedLabel);

However, I would like the button to have an icon at the top and text message at the bottom. I am using reactjs and the material-ui library which can be found here.

Answer №1

The Button component utilizes flexbox for controlling the layout and alignment of content. To align the content vertically (with the icon above the text), a simple adjustment can be made by changing the flex-direction to column.

It's important to remember that this style modification should be applied to an element within the button component, not the root element. The classes property can be used to override all styles in a component.

In this scenario, adding flexDirection: column to the label class is recommended.

Read more about customizing classes in material ui v1

Below is a functional example. I hope it proves helpful.

const [React, ReactDOM, Button, Settings, withStyles] = [window.React, window.ReactDOM, window['material-ui'].Button, ({className}) => <i className={`material-icons ${className}`}>settings</i>, window['material-ui'].withStyles]
// Ignore code above this line

const styles = theme => ({
  button: {
    height: 95, // setting height/width is optional
  },
  label: {
    // Aligns the content of the button vertically.
    flexDirection: 'column'
  },
  icon: {
    fontSize: '32px !important',
    marginBottom: theme.spacing.unit
  }
})

const CustomButton = ({ classes }) => (
  <Button
    /* Use classes property to inject custom styles */
    classes={{ root: classes.button, label: classes.label }}
    variant="raised"
    color="primary"
    disableRipple={true}
  >
    <Settings className={classes.icon} />
    Message
  </Button>
)

const WrappedCustomButton = withStyles(styles)(CustomButton)
ReactDOM.render(<WrappedCustomButton />, document.querySelector('#root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script><script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3f525e4b5a4d565e53124a567f0e110f110f125d5a4b5e110b0f">[email protected]</a>/umd/material-ui.production.min.js"></script><link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"><div id="root" />

Answer №2

An option that may not be ideal is:

.MuiIconButton-label {
  flex-direction: column
}

This could be considered bad practice as it limits flexibility in using the standard format elsewhere.

Instead, I chose to assign a class name nav-bar-icon-wrapper to the IconButton and adjust the flex direction in its parent element:

.nav-bar-icon-wrapper {
  flex-direction: column
}

.MuiIconButton-label {
  flex-direction: inherit
}

If there comes a time when I need the icon/label button to display in a standard format, I can simply add a new class default-icon-wrapper with appropriate styling:

.default-icon-wrapper {
  flex-direction: row
}

For What It's Worth (FWIW): I advocate for the BEM methodology , and recommend adding an optional modifier prop when creating components.

I have functions in a shared directory that function like this:

export function BEMifyThis(modifier) {
    return (klass) => BEMify(klass, modifier)
}

export function BEMify(klass, modifier=false) {
    if (modifier) {
      klass += ` ${klass}-${modifier}`
    }
    return klass
}

This approach allows users to access component elements as a group or individually by utilizing their modifiers throughout the component.

import {BEMifyThis} from '../shared/bem'
const BEMify = BEMifyThis(this.props.modifier)

className={"navbar__menu_item")}
transforms into
className={BEMify("navbar__menu_item")}

Therefore, a classname like navbar__menu_item would become

navbar__menu_item navbar__menu_item-logout

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the connection between serialization and JSON?

Can you explain serialization? Serialization is the process of converting an object into a stream of bytes, allowing it to be sent over a network or stored in a file. This allows the object to be reconstructed later on. What exactly is JSON? JSON stands ...

Ways to prevent the need for multiple if/else statements and repetitious function instances

Check out this code snippet in Javascript: https://pastebin.com/zgJdYhzN. The purpose of the code is to fade in text when scrolling reaches a specific point. While it does work, I want to optimize it for multiple pages without creating separate instances ...

leveraging jQuery mobile for asynchronous requests

I've been attempting to print a jQuery mobile element using ajax, but I'm running into an issue where the result isn't being encoded as jQuery mobile is intended to do. Below is a simplified excerpt of the JavaScript code responsible for t ...

a function that repeats every single second

A challenge I am facing is creating a countdown timer with a time that refreshes every second. My current implementation uses setInterval, but it only seems to run once instead of every second. Can anyone help me identify the issue in my code? var countDo ...

Executing Actions Prior to Redirecting

I am working on implementing a timer process using a custom JQuery plugin that will redirect to the login page after a specific number of minutes. Additionally, when the timer reaches zero, I need to execute a task, which in this case involves making a cal ...

struggling to send variables to jade templates with coffeescript and express.js

As a newcomer to node and express, I am currently building the front end of an application that utilizes jade as its templating engine. Despite extensive searching online and within this community, I have not been able to find a solution to a particular is ...

The background-size property in CSS does not seem to properly display on iPhones

Hello there! I'm facing an issue with my CSS code when it comes to displaying the image on Safari browser. It works perfectly fine on other browsers, but for some reason on Safari, the image doesn't show up correctly. I tried using a media query ...

How can I add text to an HTML5 SVG similar to using the HTML5 <p> tag?

I am currently working on creating dynamic rectangular boxes and I am facing some difficulties with inserting text into the shapes. The SVG text requires setting x and y coordinates in separate text tags, and doesn't have built-in width and height pro ...

Troubleshooting problem in React component: `background-repeat` is not functioning as expected

I'm having a problem with the background-repeat CSS property in my React component. I've set the backgroundRepeat property to "repeat," but it's not working as expected. The background image is not repeating like it should. Here is the style ...

JavaScript - Dynamically loaded CSS: CSS variables are not immediately accessible to JavaScript, but are successfully evaluated within the CSS itself

I am encountering an issue with dynamically loading stylesheets via JavaScript into my application. Within these stylesheets, I have various CSS variables that I need to access and modify from my JavaScript code. When the stylesheets are directly embedded ...

Which is better for cycling through a list of items: CSS or JavaScript?

Currently, I have a navigation bar set up as an unordered list (<ul>), but some list items are not visible. I want to implement functionality where clicking arrows will move the elements left or right by hiding or showing the leftmost or rightmost it ...

The following middleware is not functioning properly on a local SSL server

When I run my Nextjs app without SSL using "next dev", the middleware functions as expected without any errors. However, if I attempt to run the app with SSL enabled, an empty middleware function triggers an error. The code for the middleware function (l ...

OroCrm is ensuring that Symfony2 profiler seamlessly updates the footer data without triggering a 404 error page within a popup

As a newcomer to OroCrm, I recently installed and configured it on my DEV environment using the app_dev.php entry point. After setting up OroCrm, I immediately noticed the Symfony2 profiler bar appearing at the bottom of the interface. While this was a he ...

Issue encountered when utiliting the scrollToPlugin from GSAP in conjunction with create-react-app

Having an issue while trying to incorporate GSAP's scrollToPlugin with facebook's 'create-react-app' as I encounter the following error - Error in ./~/gsap/src/uncompressed/plugins/ScrollToPlugin.js Module not found: 'TweenLite&ap ...

Encountering an "undefined" error while implementing a registration system in Node.js and attempting to retrieve

Having recently delved into the world of javascript and nodejs, I am currently working on developing a registration system. The issue I'm facing is related to an error message indicating that "isEmail" is undefined. I have included my form validator a ...

ERROR: Module 're2' not found in './build/Release/re2' (npm)

After receiving suggestions from sonarQube, I am attempting to switch out my original regular expression with RE2. However, upon installation, the following error message appears: Error: Cannot locate module './build/Release/re2' Important note ...

When using NextJs, running the commands 'npm build' and 'npm start' can sometimes cause style inconsistencies

Currently working on a project with NextJs (sorry, no screenshots allowed). Running 'npm run dev' for development works perfectly fine, but when I switch to 'npm run build' and then 'npm start', the website displays overlappin ...

Automatically increase the height of a text area as you type beyond the maximum width limit

Is there a way to dynamically expand the textarea width as I type beyond its maximum set width without displaying a horizontal scrollbar? Here is the HTML code in its rendered form: <textarea name="CatchPhrase" class="inp ...

On the second attempt to call setState within the componentDidMount method, it is not functioning as expected

As a newcomer, I am delving into the creation of a memory game. The main objective is to fetch data from an API and filter it to only include items with image links. On level one of the game, the task is to display three random images from the fetched data ...

How can you specify the maximum width and height for a TextField in JavaFX using CSS?

Is there a way to set preferred and maximum width and height for a TextField using CSS? ...