Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Positioning material-ui label to the left with left alignment

Tags:

material-ui

I'm using the radio button components available from material-ui.com and have set labelPlacement="start". This has placed the label on the left side, but I would also like the labels to be left aligned while leaving the radio buttons on the right.

<RadioGroup
    name="switching"
    value="switching"
    onChange={this.handleEstablishingChange.bind(this)}
>
    <FormControlLabel value="switching" control={<Radio />} labelPlacement="start" label={this.props.lang().justswitching} />
    <hr />
    <FormControlLabel value="new_source" control={<Radio />} labelPlacement="start" label={this.props.lang().newsource} />
</RadioGroup>

enter image description here

like image 249
Ben McCann Avatar asked Jun 28 '19 20:06

Ben McCann


1 Answers

Here is a simple & straightforward solution to your problem using CSS override on the FormControlLabel component (which encapsulates both the label and the actual control).

We use Material-UI's makeStyles helper to define the class we'll use to override the default styling of FormControlLabel. We specifically want to target the root key (the full list of available CSS override keys for FormControlLabel is available here), hence we name our class root to benefit from destructuring and assignment simplification.

We assign the classes object returned from the useStyles hook call to the classes prop of each FormControlLabel. The long-form of that assignment would be classes={{ root: classes.root }} but because we named our class root (which is the name of the key we're targeting) we can simply write classes={classes}.

import React, { useState } from "react";
import ReactDOM from "react-dom";
import { makeStyles } from "@material-ui/core/styles";
import { RadioGroup, FormControlLabel, Radio } from "@material-ui/core";

const useStyles = makeStyles({
  root: {
    // component default is "inline-flex", using "flex" makes the
    // label + control group use the entire width of the parent element
    display: "flex",
    // component default is "flex-start", using "space-between" pushes
    // both flexed content to the right and left edges of the flexbox
    // Note: the content is aligned to the right by default because
    // the 'labelPlacement="start"' component prop changes the flexbox
    // direction to "row-reverse"
    justifyContent: "space-between",
  },
});

const App = () => {
  const [source, setSource] = useState("switching");
  const classes = useStyles();
  return (
    <div>
      <RadioGroup
        name="source"
        value={source}
        onChange={e => setSource(e.target.value)}
      >
        <FormControlLabel
          value="switching"
          control={<Radio />}
          labelPlacement="start"
          label={"Switching"}
          classes={classes}
        />
        <hr />
        <FormControlLabel
          value="new_source"
          control={<Radio />}
          labelPlacement="start"
          label={"New Service"}
          classes={classes}
        />
      </RadioGroup>
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Working codesandbox demo

Update: additional content about hooks

Say you have the following code (which will fail):

import React from "react"
import { RadioGroup, FormControlLabel, Radio } from "@material-ui/core"
import { makeStyles } from "@material-ui/core/styles"

const useStyles = makeStyles({
  root: {
    display: "flex",
    justifyContent: "space-between",
  },
})

class ComponentGenerator extends React.Component {

  // ... stuff here ...

  render() {
    const classes = useStyles() // <-- NO! Not a functional component & not
                                // top-level, hooks cannot be used here
    return (
      <RadioGroup
        name="source"
        value={source}
        onChange={this.handleEstablishingChange.bind(this)}
      >
        <FormControlLabel
          value="switching"
          control={<Radio />}
          labelPlacement="start"
          label={"Switching"}
          classes={classes}
        />
        <hr />
        <FormControlLabel
          value="new_source"
          control={<Radio />}
          labelPlacement="start"
          label={"New Service"}
          classes={classes}
        />
      </RadioGroup>
    )
  }
}

A solution is to externalize the inner component that uses hooks:

src/components/UI/MyRadio.js

import { FormControlLabel, Radio } from "@material-ui/core"
import { makeStyles } from "@material-ui/core/styles"

const useStyles = makeStyles({
  root: {
    display: "flex",
    justifyContent: "space-between",
  },
})

const MyRadio = ({ value, label }) => {

  const classes = useStyles() // <-- YES! Functional component & top-level

  return (
    <FormControlLabel
      value={value}
      control={<Radio />}
      labelPlacement="start"
      label={label}
      classes={classes}
    />
  )
}

export default MyRadio

and in your component generator:

src/components/ComponentGenerator.js

import React from "react"
import { RadioGroup } from "@material-ui/core"
import MyRadio from "./UI/MyRadio"

class ComponentGenerator extends React.Component {

  // ... stuff here ...

  render() {
    return (
      <RadioGroup
        name="source"
        value={source}
        onChange={this.handleEstablishingChange.bind(this)}
      >
        <MyRadio
          value="switching"
          label={"Switching"}
        />
        <hr />
        <MyRadio
          value="new_source"
          label={"New Service"}
        />
      </RadioGroup>
    )
  }
}
like image 71
Thomas Hennes Avatar answered Oct 26 '22 10:10

Thomas Hennes