I am building a webpage with React and Material-UI. I have a TextField element and I want to remove the arrow buttons - if I were using CSS I would use the following code:
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
But I want to style the page using CSS in JS where I use export default withStyles(styles)(FormPersonalDetails). How do I do this?
`
const styles = theme => ({
number: {
// styling code goes here//
}
});
render() function:
const { classes } = this.props;
return (
<TextField className={classes.number} />
)
There are a few syntax options. I have included two options below. The first one uses className on TextField and then targets the descendant input element. The second one applies the className directly to the input element via the TextField inputProps property.
The & is used in both to refer to the parent selector (i.e. the element that the class is being applied to).
import React from "react";
import ReactDOM from "react-dom";
import TextField from "#material-ui/core/TextField";
import { withStyles } from "#material-ui/core/styles";
const styles = theme => ({
number: {
"& input::-webkit-outer-spin-button, & input::-webkit-inner-spin-button": {
"-webkit-appearance": "none",
margin: 0
}
},
input: {
"&::-webkit-outer-spin-button, &::-webkit-inner-spin-button": {
"-webkit-appearance": "none",
margin: 0
}
}
});
function App({ classes }) {
return (
<div className="App">
<TextField type="number" className={classes.number} />
<br />
<TextField type="number" inputProps={{ className: classes.input }} />
</div>
);
}
const StyledApp = withStyles(styles)(App);
const rootElement = document.getElementById("root");
ReactDOM.render(<StyledApp />, rootElement);
Related
I have tried to display a search icon inside my search bar, but it isn't working. my code is
import React, { useEffect } from "react";
//31915c5e
const API_URL = 'http://www.omdbapi.com?apikey = 31915c5e'
const App = () => {
const searchMovies = async (title) => {
const response = await fetch(`${API_URL}&s=${title}`);
const data = await response.json();
console.log(data.search);
}
useEffect(() => {
searchMovies('spiderman');
}, []);
return (
<div className="app">
<h1>MovieLand</h1>
<div className="search">
<input
placeholder="search for movies"
/>
/*https://react-icons.github.io/react-icons/icons?name=gi*/
<img
src={SearchIcon}
alt="search"
/>
</div>
</div>
);
}
export default App;
showing a search icon inside my search bar.
on the browser it displays 'SearchIcon' is not defined no-undef
There are different ways of doing this, I would either install #fortawesome/react-fontawesome and #fortawesome/free-solid-svg-icons and do it with that, or, the option I would prefer that consists in using inline styles, positioning the icon as a background of the input tag; it would be something like this:
import React, { useState } from "react";
import searchIcon from "path/to/search-icon.svg";
function SearchInput() {
const [searchTerm, setSearchTerm] = useState("");
return (
<div>
<input
type="text"
placeholder="Search"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
style={{
padding: "0.5rem 0.5rem 0.5rem 2rem",
background: `url(${searchIcon}) no-repeat`,
backgroundSize: "1.5rem",
backgroundPosition: "0.5rem center",
}}
/>
</div>
);
}
export default SearchInput;
This will create an input element with a search icon as its background, and the icon will be positioned inside the input at the center left of the input field.
You can adjust the position of the icon using the background-position property and you can adjust the size of the icon using the background-size property.
I am working with a programmatically generated form (from a json file) with multi steps. I followed the react-hook-form wizard guide and I combine it with nested component to create the components I need to create the form and its pages.
The problem I have is that if I wrap my component with a Controller, when I submit my form, I have two ids, one with the right id and an undefined value (which is wrong), the second with the wrong id but the right value
import { Picker } from '#react-native-picker/picker'
import { useFormContext } from 'react-hook-form'
import styled from 'styled-components/native'
import { useState } from 'react'
type SelectFieldProps = {
element: SurveyPageComponent
}
const SelectField = ({
element: { options, position, defaultValue, label, type, id }
}: SelectFieldProps) => {
const { register } = useFormContext()
const [selectedField, setSelectedField] = useState<unknown>(defaultValue)
return (
<>
<Label>{label}</Label>
<Select
{...register(`${id}`)}
selectedValue={selectedField}
onValueChange={(itemValue) => setSelectedField(itemValue)}
>
{options.map(({ label, id }) => (
<Picker.Item
key={`${type}-${position}-option-${position}-${label}-${id}`}
label={label}
value={id}
/>
))}
</Select>
</>
)
}
const Label = styled.Text`
width: 100%;
text-align: center;
`
const Select = styled(Picker)`
width: 100%;
`
export default SelectField
This gives me after submitting:
Object {
"6": undefined,
}
If I wrap my Input with a controller like this:
import { Picker } from '#react-native-picker/picker'
import { Controller, useFormContext } from 'react-hook-form'
import styled from 'styled-components/native'
type SelectFieldProps = {
element: SurveyPageComponent
}
const SelectField = ({
element: { options, position, required, defaultValue, label, type, id }
}: SelectFieldProps) => {
const {
control,
register,
formState: { errors }
} = useFormContext()
return (
<>
<Label>{label}</Label>
<Controller
control={control}
render={({ field: { onChange, value } }) => (
<Select
{...register(`${id}`)}
selectedValue={value}
onValueChange={(itemValue) => onChange(itemValue)}
>
{options.map(({ label, id }) => (
<Picker.Item
key={`${type}-${position}-option-${position}-${label}-${id}`}
label={label}
value={id}
/>
))}
</Select>
)}
name={label}
rules={{ required }}
defaultValue={defaultValue}
/>
{errors[`${type}-${position}-${label}`] && (
<span>This field is required</span>
)}
</>
)
}
const Label = styled.Text`
width: 100%;
text-align: center;
`
const Select = styled(Picker)`
width: 100%;
`
export default SelectField
I get after submitting:
Object {
"6": undefined,
"Avez-vous apprécié ce nouveau client ?": 2,
}
I just cannot understand why would the controller adds another line to my submitted data and I didn't found an answer to this anywhere.
The only way I made it work is to add a setValue(`${id}`, itemValue) in my onValueChange property.
Can someone point me in the right direction please ?
I found why, I don't need to register my field, but I need to put the correct name in my controller (in that case my id):
name={`${id}`}
When contentEditable is set to true, only the element that is focused can be selected. I'm trying to make cells that function like they do in excel. I'd like to be able to edit the cell on a single click, otherwise I would just set contentEditable with state and select them as regular div elements. I thought about doing something with onMouseOut to change the state to false, but thet doesn't seem to work.
App component:
import { useState, useRef, useEffect } from "react";
import Cell from "./Cell";
export default function App() {
const testRef = useRef();
const [st, setSt] = useState(false);
useEffect(() => {
if (st) testRef.current.focus();
}, [st]);
return (
<div style={{ display: "flex" }}>
<Cell tabindex="1" />
<Cell tabindex="2" />
<Cell tabindex="3" />
</div>
);
}
Cell component:
import "./styles.css";
import { useState, useRef, useEffect } from "react";
export default function Cell() {
const [editing, setEditing] = useState(true);
const testRef = useRef();
const stopEditing = () => setEditing(false);
const startEditing = () => setEditing(true);
return (
<div>
<div
ref={testRef}
contentEditable={editing}
// onBlur={stopEditing}
// onMouseUp={stopEditing}
onMouseOver={startEditing}
style={{
display: "flex",
border: "1px solid #696969",
width: "100px",
height: "25px",
cursor: "cell",
margin: "2px"
}}
></div>
<p>{editing.toString()}</p>
</div>
);
}
https://codesandbox.io/s/unruffled-rain-i0v40g?file=/src/Cell.js:0-734
<div class = "div1" onmousedown = "selectFunction()">
function selectFunction() {
document.getElementByClassName("div1")[0].style.color = "red"; }
Maybe something like this? However, this will only work for one of the div's, try applying them to all the div's. This might not work, I'll edit it if it does not. (All this does it highlight the div red, probably won't work if you want to select multiple div's at once)
I was previously using Material UI's Button component, which has the disable property. Basically that prop allows the button to be disabled based on a boolean. So if true, then it is disabled. However, now I want to switch to the Material UI Link component which is also a button, but it looks like a text. It does the same thing a button does, but looks like a link. However, it does not have the disable property or it seems because I dont see it as a possible property in the Material UI docs. Is there any work around for this?
*Note - This is not from the React Router Dom library. I am using the Link from Material UI Library for React. Just so there is no confusion.
<Link
hover
underline="hover"
variant="body2"
onClick={
this.buyAll
}>
Buy All Products
</Link>
Material-UI's Link renders as an <a> element by default. If you want it to render as a <button> (which would be appropriate when you are specifying onClick and not specifying href), then you need to specify component="button". Once you have done that, the disabled prop will work as expected with the caveat that Material-UI's Link doesn't have any styling for a "disabled" look; so if you want the link to look different when it is disabled, you will need to customize the styles for that state.
Below is a working example including some sample disabled styling:
import React from "react";
import { makeStyles, withStyles } from "#material-ui/core/styles";
import MuiLink from "#material-ui/core/Link";
import Typography from "#material-ui/core/Typography";
const useStyles = makeStyles((theme) => ({
root: {
"& > * + *": {
marginLeft: theme.spacing(2)
}
}
}));
const Link = withStyles({
root: {
"&[disabled]": {
color: "grey",
cursor: "default",
"&:hover": {
textDecoration: "none"
}
}
}
})(MuiLink);
export default function Links() {
const classes = useStyles();
return (
<Typography className={classes.root}>
<Link component="button" onClick={() => console.log("hello")}>
Link
</Link>
<Link
component="button"
disabled
onClick={() =>
console.log(
"I'm disabled so this doesn't appear in the console when this is clicked."
)
}
>
Disabled Link
</Link>
</Typography>
);
}
Thank #RyanCogswell. I tried to improve his answer by defining a custom theme, based on MUI's default theme and using pointer-events: none:
import { createTheme } from '#mui/material/styles'
const { palette } = createTheme() // MUI's default theme
const theme = createTheme({ // Our app's custom theme
MuiLink: {
styleOverrides: {
root: {
'&[disabled]': {
color: palette.action.disabled,
pointerEvents: 'none',
},
},
},
},
})
import { Link } from '#mui/material'
//...
<Link
disabled
to='https://stackoverflow.com/a/72479343/5318303'
>
Disabled link
</Link>
In my React app, I use React JSS for styling. Suppose I have these two files (skipping imports and another non interesting stuff).
This is App.js:
const styles = {
root: {
backgroundColor: '#ffffff',
},
header: {
backgroundColor: '#ff0000',
}
};
class App extends Component {
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<Header classes={{ root: classes.header }}/>
</div>
);
}
}
export default withStyles(styles)(App);
and this is Header.js:
const styles = theme => ({
root: {
backgroundColor: '#0000ff',
padding: '1em',
},
});
class Header extends Component {
render() {
const { classes } = this.props;
return (
<header className={classes.root}>
Hello header
</header>
);
}
}
export default withStyles(styles)(Header);
What I would like to have is "overriding" the style of the root component of Header without overwriting it completely. I can do either of two things:
use <Header className={classes.header}/>, which results in the header element having the class App-root-0-1-2, which means the background is blue with the padding;
use <Header classes={{ root: classes.header }}/> (as above), which results in the header element having the class App-header-0-1-2, which means the background is read without padding.
It seems I can only have either the style defined by the component OR the one that the parent defines to override it. However, I would like to extend the internal style with the one passed by the parent - of course, with the parent taking precedence in conflicts. In this case, I wish to have the red background with the padding.
How can I achieve that? Is it impossible - do I need to pass the editable style as a property?
You can provide an external class name and use classnames (https://github.com/JedWatson/classnames) (or just inline them) to conditionally render this class name if present:
import classNames from "classnames";
const styles = theme => ({
root: {
backgroundColor: '#0000ff',
padding: '1em',
},
});
class Header extends Component {
render() {
const { classes, className } = this.props;
return (
<header
className={classNames({
[classes.root]: true,
[className]: className
})}>
Hello header
</header>
);
}
}
export default withStyles(styles)(Header);
Then use it:
<Header className={classes.myParentClass} />
This will result in a class names, e.g. Header-root-0-1-2 App-myParentClass-0-4-3