I'm using react-native-web with expo and react-native-paper (material ui)
My problem is textarea on focus outline property in the compiled web version so I need to get rid of this blue borders. Normally I'll do
textarea:focus {
outline:none!important
}
With react-native we cannot use css and only jss but how to do it for this property?
<TextInput
label='Email'
value={this.state.text}
onChangeText={text => this.setState({ text })}
style={???}
/>
working example
You can't do such with inline style of React components. There're 2 ways of achieving this.
Option 1: put your styles inside the component's state and use onFocus to manipulate it
Option 2: use a CSS in JS library like https://www.styled-components.com/
This might help
state = {
backgroundColor: 'green'
}
onFocus() {
this.setState({
backgroundColor: 'green'
})
}
onBlur() {
this.setState({
backgroundColor: '#ededed'
})
}
<TextInput
onBlur={ () => this.onBlur() }
onFocus={ () => this.onFocus() }
style={{ height:60, backgroundColor: this.state.backgroundColor }} />
If your using react-jss you can specify event styling like focus and hover like this &:hover &:focus
Related
I am currently building a component library for a project following given design specifications and therefore am extending the default button theme in a separate button.ts which contains something like this:
const solid: SystemStyleFunction = (props) => ({
bg: mode("tealLight", "teal")(props),
color: "bgDark",
borderRadius: "20px",
_active: {
bg: mode("white", "bgDark")(props),
color: mode("bgDark", "white")(props)
},
_disabled: {
bg: "lightGrey",
color: "grey"
}
});
const Button : StyleConfig = {
defaultProps: {
size: "md"
},
variants: {
solid: solid,
}
};
export default Button;
Works like a charm so far.
Now the given design requires that an arrow is to be shown on hover to the right of the button's label.
Back in the days of hand-written (S)CSS, i would have just added a pseudo-element only visible on :hover – here, of course, i am now looking into adding _hover: { ... } to the above SystemStyleFunction-config.
According to the Chakra UI docs, showing an icon on a standard form button can easily be achieved via the rightIcon or leftIcon prop. I do have the icon component ready at hand, however:
The leftIcon and rightIcon prop values should be react elements NOT strings.
So how can the hover-only icon be achieved then ...
can i use React.createElement(...) to define the element right there (or in the StyleConfig object at the end of my file)?
can i convert my button.ts into a button.tsx and then add the icon-element in JSX-style syntax?
is there an alternative way of setting the icon element (because the documentation says "should", not "must")
or is this impossible to be done with my styled <Button> and a completely different approach is needed (if so, kindly advise)?
I did this way :
<InputGroup
alignItems="center"
bgColor="#e27065"
w={200}
borderRadius="3"
_hover={{ bg: "white", svg: { fill: "black" } }}
>
<InputLeftElement
children={<BsSearch color="white" />}
height={8}
boxSize={7}
alignItems="center"
padding={1}
/>
<Input
type="text"
placeholder="Search"
_placeholder={{ color: "white" }}
_hover={{ _placeholder: { color: "black" } }}
height={7}
borderRadius="3"
/>
</InputGroup>
I'm using MUI textfield per the documentation here: https://mui.com/components/text-fields/. while there are plenty of docs on changing the font of the input text, I have yet to see any docs or resources on how to make the carrot fatter. I'm looking for a style that simulates the console, and I have provided an image below. Below is the code for textinput I'm using, rather standard:
const translucent = 'rgba(255,255,255,0.1)';
const useStyles = makeStyles((theme: Theme) => createStyles({
wrapForm : {
display: "flex",
justifyContent: "center",
width: "95%",
margin: `${theme.spacing(0)} auto`,
// borderBottom: `0.8px solid ${translucent}`, // #TODO: remove this
},
wrapText : {
width: "100%"
},
button: {
margin: theme.spacing(1),
},
multilineColor:{
color:'white',
borderColor: `white !important`,
filter: 'blur(0.8px)'
},
overLayContainer: {
display: 'grid',
},
overLayContainerInner: {
gridArea: '1 / 1',
},
}));
/******************************************************
#View
******************************************************/
export const TextInput = (props) => {
const classes = useStyles();
return (
<>
<form className={classes.wrapForm} noValidate autoComplete="off">
<TextField
className = {classes.wrapForm}
fullWidth
multiline
InputProps={{className: classes.multilineColor, disableUnderline: true}}
rows = "1"
margin = "normal"
/>
</form>
</>
)
}
The reason that there's no documentation on how to make a fatter "caret" is because this is not currently supported in browsers. You can change the caret color using CSS (eg. caret-color: red;), but if you want to mimic a console's "fat" caret, you may have to add your own element to the screen and then move it based on the input entered. Here is an old example of one way to do it and another which would also require your own JS implementation.
There is a proposed revision for caret-shape: block;, which appears to be what you're looking for, but that is not currently supported.
I wanted to change the icon in material UI's AutoComplete. I was not able to find any documentation to customize it.
Basically the two icons, marked with 1 and 2. I am new to Material Ui and would like to know if this can be done and how.
Codepen for the same is https://codesandbox.io/s/material-demo-9vhkq
Explain
If you check the DOM structure of it, you would find two button which have the class of something kind like
className="MuiButtonBase-root MuiIconButton-root MuiAutocomplete-clearIndicator MuiAutocomplete-clearIndicatorDirty"
className="MuiButtonBase-root MuiIconButton-root MuiAutocomplete-popupIndicator"
Inside of them you can find the specific className
MuiAutocomplete-clearIndicator
MuiAutocomplete-popupIndicator
Which you can refer to Material-UI Autocomplete css api document
clearIndicator
popupIndicator
By setting styles to it, you can change it's styles, and the icons.
Code
const useStyles = makeStyles(theme => ({
root: {
backgroundColor: "yellow"
},
clearIndicator: {
backgroundColor: "gray",
"& span": {
"& svg": {
"& path": {
d: "path('M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z')" // your svg icon path here
}
}
}
},
popupIndicator: {
backgroundColor: "blue"
}
}));
<Autocomplete
id="combo-box-demo"
options={top100Films}
getOptionLabel={option => option.title}
style={{ width: 300 }}
classes={{
clearIndicatorDirty: classes.clearIndicator,
popupIndicator: classes.popupIndicator
}}
Example:
You can change the popup icon with the API using the popupIcon property:
popupIcon={<ImportContacts />}
Shows as:
Full API found here:
https://material-ui.com/api/autocomplete/
I found that the convention to changing css of TextInput is by changing the component's state using onFocus and onBlur props.
I learned it from this post.
However, though successful I had to do some ugly workaround:
I moved the state management to my form component instead of putting it in my TextInput wrapper
I had to implement a hack componentDidUpdate() to refocus the TextInput, something like this
componentDidUpdate() {
this.props.isActive ? setTimeout(() => this.input.focus(), 100) : null
}
Now everything is working as expected, except that the keyboard would flicker upon moving to the next TextInput by using onSubmitEditing props.
Here's my code snippet related to this case:
in my form component I instantiate the input wrapper component like so within a loop, i.e. fields.map()
<AuthTextInput
ref={ref => inputRefs[key] = ref}
key={key}
label={label}
onFocus={() => this.setState({ currentInput: key })}
isActive={this.state.currentInput === key}
onSubmitEditing={() => (idx + 1) < fields.length && fields[idx + 1].type !== 'selection' ? inputRefs[fields[idx + 1].key].focus() : this.setState({ currentInput: null })}
blurOnSubmit={(idx + 1) === fields.length || fields[idx + 1].type === 'selection'}
returnKeyType={(idx + 1) === fields.length || fields[idx + 1].type === 'selection' ? 'done' : 'next'}
autoCapitalize={autocaps}
secureTextEntry={secureTextEntry}
placeholder={placeholder}
keyboardType={keyboard}
containerStyle={[{ width: orientation() === 'landscape' ? 0.5 * windowWidth() : windowWidth() * 0.7, height: normalize(70), marginVertical: normalize(10) }]}
leftIcon={<Image style={{ width: normalize(50), height: normalize(50), marginTop: 25 }} source={fieldIcon} />}
onChangeText={(text) => this.onChange(key, text)}
value={this.state[key] ? this.state[key]['value'] : ''}
error={this.state.error[key]}
/>
The content of AuthTextInput is like so:
import React, { Component } from 'react';
import { View, StyleSheet, TextInput, Text } from 'react-native';
import { Input } from 'react-native-elements';
import { isEmpty } from '../utils/validate';
import { windowWidth, fontSize, fontFamily, normalize, color } from '../theme/baseTheme';
import IconWrapper from './IconWrapper';
const styles = StyleSheet.create({
container: {
flex: 1
},
inputContainer: {
borderBottomWidth: 0,
},
inputStyle: {
fontSize: fontSize.regular + 2,
fontFamily: fontFamily.bold,
paddingLeft: normalize(15),
borderBottomWidth: 1
},
errorStyle: {
color: color.red,
fontSize: fontSize.small - 4,
fontFamily: fontFamily.bold,
fontWeight: 'bold',
marginLeft: normalize(75)
},
focusedContainer: {
borderWidth: 1,
borderColor: color.light_blue,
borderRadius: 8
}
});
class AuthTextInput extends Component {
constructor(props) {
super(props);
this.state = {
secureText: this.props.secureTextEntry,
}
}
componentDidUpdate() {
this.props.isActive ? setTimeout(() => this.input.focus(), 100) : null
}
focus() {
this.input.focus();
}
render() {
const { secureTextEntry, value, containerStyle, isActive } = this.props;
return (
<Input
{...this.props}
ref={ref => this.input = ref}
disableFullscreenUI={true}
secureTextEntry={this.state.secureText}
containerStyle={[styles.container, containerStyle, isActive ? styles.focusedContainer : null]}
inputContainerStyle={styles.inputContainer}
inputStyle={styles.inputStyle}
rightIcon={
secureTextEntry && value !== '' ?
this.state.secureText ?
<IconWrapper name="visibility" size={20} color={color.light_grey} style={{ justifyContent: 'center' }} onPress={() => this.setState({ secureText: false })} />
:
<IconWrapper name="visibility-off" size={20} color={color.light_grey} style={{ justifyContent: 'center' }} onPress={() => this.setState({ secureText: true })} />
:
null
}
errorMessage={!isEmpty(this.props.error) ? this.props.error : null}
errorStyle={[styles.errorStyle, this.props.errorStyle]}
/>
);
}
}
export default AuthTextInput;
The problem I found mainly lies in the first snippet, where I wrote onFocus={() => this.setState({ currentInput: key })} which re-renders the form component and somehow removing the focus. Hence, the refocusing in AuthTextInput's componentDidUpdate.
I thought when my form component re-renders, all the old AuthTextInput are getting destroyed, so I tried doing autoFocus={this.props.isActive} too in AuthTextInput, but it wasn't successful because componentDidMount itself was never called, which implies they didn't get destroyed, just updated.
This made me wonder, if it didn't get destroyed and remade, what made the focus went away?
I mean, I did the same thing to set the value by doing this onChangeText={(text) => this.onChange(key, text)} and calling setState there. and in that case, the component didn't lose focus.
Anyhow, I would love to know if anyone can either:
show me what made the focus go away OR
using my workaround above to refocus after setting the form state, prevent keyboard from flickering (dismissing and reappearing within a short interval).
Thanks in advance!
UPDATE:
I found that in my TextInput wrapper, when it is updated the FIRST TIME using setState from onFocus callback, it always calls onBlur right away, which is weird and I couldn't find anything that calls onBlur the first time both in mine or the library react-native-element's code.
UPDATE2:
Turns out even when I already disabled onBlur from being called and updating the component once again right after onFocus, the input still loses focus, and I have no idea what's causing it. I checked both the form's and the input's component didupdate and they didn't fire, odd...
So I guess I just have to find out what's stealing the focus when my onFocus updates the input state
FINAL UPDATE:
INTERESTING FIND!!! isActive ? styles.focusedContainer : null this is the culprit, for some reason this is triggering blur() event. None of the answers below can recreate this because none of them modifies the css styling of this component.
I think this happens because containerStyleProps is passed as the parent's View component props to the actual TextInput component by react-native-elements. This causes rerendering at that level causing TextInput to rerender too.
But problem persist, how should I go about solving this issue if simply updating my style triggers the TextInput rerendering? Is there any way to tap into the TextInput's shouldUpdateComponent() hook?
Thanks again for any opinion posted here that helped me gain this insight
I tried to implement the skeleton of the problem. In the below example the input does not loses the focus, works as expected.
class App extends React.Component {
state = {
isFocus: 'no focus'
}
handleFocus = () => {
this.setState({ isFocus: 'got focus' })
}
handleBlur = () => {
this.setState({ isFocus: 'no focus' })
}
render() {
return <input onFocus={this.handleFocus} onBlur={this.handleBlur} value={this.state.isFocus} />;
}
}
ReactDOM.render(<App />, document.getElementById('root'))
input:focus {
box-shadow: 5px 5px 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I had the same problem, specifically on Android - iOS seems to be unaffected at the time of writing this.
onBlur gets called when the TextInput or it's container is rendering differently based on State variables... as you noted, in your case it was the following:
isActive ? styles.focusedContainer : null
To get around this and keep your setState in onFocus and onBlur, and still style your component beautifully based on state, I managed to fix this issue by separating focus styling from the input, and make it styled on a sibling view instead of a parent view or the input view itself:
<View>
<View style={ isActive ? styles.focused : styles.unfocused } />
<Input/> // <-- do not use state to style this.
</View>
This will avoid the onBlur getting called, however, you will obviously need to correctly position the "un/focus styled" View behind the Input view to line them up.
For this, use styles for position='absolute', width='100%', height='100%'
E.g:
const styles = StyleSheet.create({
inputView: {
width='100%',
height='100%'
}
focusView: {
position: 'absolute', // <--- this is the key
width: '100%',
height: '100%'
}
}
I have been trying to work out how to style a material-ui TextField component.
<TextField
id="email"
label="Email"
className={classes.textField}
value={this.state.form_email}
onChange={this.handle_change('form_email')}
margin="normal"
/>
My classes are created as follows:
const styles = theme => ({
textField: {
width: '90%',
marginLeft: 'auto',
marginRight: 'auto',
color: 'white',
paddingBottom: 0,
marginTop: 0,
fontWeight: 500
},
});
My problem is that I can not seem to get the colour of the text field to change to white. I seem to be able to apply styling to the overall text field (because the width styling works etc)... but I think the problem is that I am not applying the styles further down the chain and into the actual input.
I have tried to look at the other answers dealing with passing inputProps but have had no success.
Have tried everything to the best of my ability but think I need to ask if anyone knows what I am doing wrong.
What it currently looks like
You need to add the InputProps property to the TextField.
const styles = theme => ({
textField: {
width: '90%',
marginLeft: 'auto',
marginRight: 'auto',
paddingBottom: 0,
marginTop: 0,
fontWeight: 500
},
input: {
color: 'white'
}
});
JSX:
<TextField
id="email"
label="Email"
className={classes.textField}
value={this.state.form_email}
onChange={this.handle_change('form_email')}
margin="normal"
InputProps={{
className: classes.input,
}}
/>
As an aside, you can also style the label or use an override as described here.
All the answers here shows how to style things with InputProps or inputProps, but no one explained why, and how it works. And no one explained whats the difference between inputProps and InputProps
<TextField
variant="outlined"
// inputProps are used to pass attributes native to the underlying
// HTML input element, e.g. name, id, style.
inputProps={{
style: { textAlign: 'center' },
}
// InputProps (capital I) passes props to the wrapper Material
// component. Can be one of the following: Input, FilledInput,
// OutlinedInput. You can pass here anything that the underlying
// Material component uses: error, value, onChange, and classes.
InputProps={{
// Usually you don't need className, the `classes` object will
// be sufficient. However, you can also use it and this will
// add your class to the div of the InputBase.
className: styles.slider_filter_input,
classes: {
root: classes.root
focused: classes.focused
// The list of keys you pass here depend on your variant
// If for example you used variant="outlined", then you need
// to check the CSS API of the OutlinedInput.
}
}}
/>
Here is a working codesandbox showing the ideas above.
This is a solution with inline styles:
<TextField
style={{
backgroundColor: "blue"
}}
InputProps={{
style: {
color: "red"
}
}}
/>
I'd suggest keeping your style within a theme.
const theme = createMuiTheme({
overrides: {
MuiInputBase: {
input: {
background: "#fff",
},
},
},
});
It really depends on what exactly are you trying to change.
The documentation has a bunch of examples on custom TextFields, take a look at them here:
https://material-ui.com/demos/text-fields/#customized-inputs
More information about customization can be found here:
https://material-ui.com/customization/overrides/
and
https://material-ui.com/customization/themes/
Have you tried using !important for the color changes? I had the same problem when I tried to set a default color for the border of an outlined TextField
Take a look at this: https://stackblitz.com/edit/material-ui-custom-outline-color
You cann pass styles to any of the children elements in the hierarchy:
TextField > Input > input (HTML element)
Notice the uper or lower case in InputProps vs. inputProps
// pass styles (or props) to the Input component
<TextField InputProps={{className: classes.input}} />
// pass styles (or props) to the inner input element
<TextField inputProps={{className: classes.input}} />
<TextField
color="whitish"
label="Enter Your Name"
type="Text"
InputLabelProps={{
style: { color: "white" },
}}
sx={{
".css-x2l1vy-MuiInputBase-root-MuiOutlinedInput-root": {
color: "white",
},
}}
InputProps={{
sx: {
".css-1d3z3hw-MuiOutlinedInput-notchedOutline": {
border: "2px solid white",
},
"&:hover": {
".css-1d3z3hw-MuiOutlinedInput-notchedOutline": {
border: "2px solid white",
},
},
},
}}
size="medium"
variant="outlined"
fullWidth
value={name}
onChange={(e) => {
setName(e.target.value);
}}
/>
Customize on_hover,color,border TextField
Try using the inputStyle prop on TextField. From the docs...
inputStyle (object) - Override the inline-styles of the TextField's input
element. When multiLine is false: define the style of the input
element. When multiLine is true: define the style of the container of
the textarea.
<TextField inputStyle={{ backgroundColor: 'red' }} />
As of MUI V5, you can use the sx prop to change style settings. You still need to use inputProps to pass down those props to the input field. You could consider doing it like this:
<TextField
sx={{ marginTop: 10 }}
inputProps={{ sx: {color: '#fff'} }}
/>
The SX prop in MUI V5
Try using the FilledInput component instead of TextField. Then you can use simple inline styling like this:
style={{color: 'white' }}
This also will lighten the placeholder text... hooray.
Give a classname to the textfield.
<TextField
className={styles.search_bar}
autoComplete={"off"}
InputProps={{
endAdornment: (
<Box className={'search_icon_container'} component={"span"}>
<IconButton>
<CiSearch fontSize={icon_default_size} />
</IconButton>
</Box>
),
}}
size={"small"}
placeholder="Search"
/>
Do this in your CSS file.
.search_bar div{
border-radius: 25px;
width: 45vw;
padding-right: 0;
}
It worked for me. :)
Output