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

Error: LocalStorage could not be located in Next.js

I'm a beginner in Next.js and I am facing an issue with unauthorized requests while trying to inject data from my API. Everything seems to be working fine except for some requests that are still returning as unauthorized. In order to access my API, I ...

Enable a VueJS directive on-the-fly from a separate directive

My goal is to simplify the process of binding a form control to vuejs by creating a directive that handles all necessary events for tracking changes in a form field. Rather than manually adding multiple event listeners like this: <input type="text" na ...

The findOneAndUpdate function in MongoDB is adding a new record into the database

Whenever I make an update API call, I just need to update the serviceActiveFlag status. After the update API call, a new document with an empty vehicle array is created, as shown below: _id:59c76073c11d3929148f500f vehicle:Array _v:0 The ID field will ov ...

React Radio Reference

I am using a radio input and want to display the result on the console using refs. Even when I select the first value, I always get the second one. Below is the constructor: this.inputKelamin = React.createRef(); It is rendered like this: <div> ...

What is the best way to vertically center an amp-img element?

I'm attempting to vertically center an <amp-img> within a div. <div class="outer" style="height: 100vh"> <amp-img class="inner" layout="responsive"></amp-img> </div> I have tried various methods so far, but none seem ...

How can we use response.render in Express.js to render HTML on the client side?

I have set up a simple Express.js application with the following routes: router.get('/', function(req, res){ res.render('login'); }); Everything is working fine - when I log into the main page on my localhost, the HTML fro ...

How can you extract the text associated with the chosen value in a dropdown list implemented in JavaScript?

Hello, I've been having difficulty extracting the value from a dropdown list created using the FacetWP plugin. Despite extensive research and numerous attempts using various methods to retrieve the text value from the list, I have not been successful. ...

Using jQuery to retrieve the HTML code for links

I am looking for a way to extract HTML links from a specific div without relying on regular expressions. Here is an example scenario: <div>Please review the links provided in the content. For instance, <a href="http://en.wikipedia.org/wiki/Apple ...

What is the process for extracting JSON values by specifying keys within a nested JSON structure?

I am attempting to extract specific JSON values for particular keys from a JSON structure. I have made the following attempt: var jsonstring; jsonstring = JSON.stringify(myjsonObjectArray); alert(jsonstring);//displaying the JSON structure below jsonstri ...

Using the v-for directive to loop through a list of items and adding a v-autocomplete with

I am facing a challenge with using a dropdown menu within a loop to select the region for each office in my list of offices. The problem lies in passing the index value to the updateRegion method so that I can correctly associate the selected region with t ...

Python Flask login screen not showing error message

Currently, I'm in the process of developing a login screen that incorporates Bootstrap and utilizes jQuery keyframes shaking effect. The backend functionality is managed by Flask. However, I seem to be encountering an issue where the error message "Wr ...

When viewing my website on a mobile device, all elements that are supposed to be hidden on the desktop version are displayed properly. However, when I resize the

I have implemented code in my css file to hide specific items from the topbar on my website. When I view the site on my desktop and inspect it with mobile view, the hidden items appear correctly concealed. However, when I access the website on my phone, ...

"Encountered the following error message: "Error [ERR_HTTP_HEADERS_SENT]: Unable to modify headers once they have been sent to the client" while attempting

My attempts to set a cookie when someone inputs the correct key (1234) are resulting in an error message: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client. I'm confused on what steps to take next. I've tried r ...

Inserting a line break in real-time within a JSX statement

Currently working on a React application that retrieves song lyrics from an API. The API provides me with a lyrics_body attribute as a string, which I use to showcase the lyrics on the webpage. However, when React renders it, the format is not ideal becau ...

Tips for implementing a settimeout function in a VUEJS script

I'm currently working on my first Vue.js application and I'm facing an issue with the initial data upload in the script. After modifying the data received from a database call, I encounter an error during the page's initial load which resolv ...

Dealing with JSON data retrieved from a Django QuerySet using AJAX

I am utilizing a Django QuerySet as a JSON response within a Django view. def loadSelectedTemplate(request): if request.is_ajax and request.method == "GET": templateID = request.GET.get("templateID", None) ...

What is the best way to replicate a synchronous ajax call? (mimicking synchronous behavior with asynchronous methods)

Given that a "native" synchronous ajax call can block the user interface of the browser, it may not be suitable for many real-world scenarios (including mine). I am curious to know if there is a way to mimic a synchronous (blocking) ajax call using an asy ...

Difficulty Loading Static JavaScript File in Express.js

Currently in the process of setting up an express server with create-react-app. Encountering this error in the console: Uncaught SyntaxError: Unexpected token < bundle.js:1 Upon clicking the error, it directs me to the homepage htm ...

Creating a zebra-striped list using CSS can be done by styling even and odd list items differently

I am facing an issue with Angularjs and the table tag when using group loops. The problem arises in achieving correct zebra striping for the list. How can I solve this to ensure the zebra pattern is applied correctly? <table> <tbody> <tr ...

What's the reason this picture isn't displaying in its full size?

I am having trouble adjusting the size of this image to fit the full width, but there seems to be some remaining space on the right side. Category: CSS/HTML /* Header */ .header { background: url('https://picsum.photos/1920/1080') center ...