Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a PasswordWidget to MUI #4274

Open
1 task done
TheOneTheOnlyJJ opened this issue Aug 15, 2024 · 5 comments
Open
1 task done

Add a PasswordWidget to MUI #4274

TheOneTheOnlyJJ opened this issue Aug 15, 2024 · 5 comments
Labels
awaiting response feature Is a feature request

Comments

@TheOneTheOnlyJJ
Copy link

Prerequisites

What theme are you using?

mui

Is your feature request related to a problem? Please describe.

I found out that there is no PasswordWidget in the @rjsf/mui package. Given how similar to a simple TextField such a widget is, can we add it to the standard distribution?

Describe the solution you'd like

No response

Describe alternatives you've considered

No response

@TheOneTheOnlyJJ TheOneTheOnlyJJ added feature Is a feature request needs triage Initial label given, to be assigned correct labels and assigned labels Aug 15, 2024
@nickgros
Copy link
Contributor

nickgros commented Aug 17, 2024

@TheOneTheOnlyJJ Why would this be needed? The core PasswordWidget works with MUI as it passes the correct prop to BaseInputTemplate, which then gets passed to MUI's TextField. See the playground with the MUI v5 theme. The password field already works.

@nickgros nickgros added awaiting response and removed needs triage Initial label given, to be assigned correct labels and assigned labels Aug 17, 2024
@TheOneTheOnlyJJ
Copy link
Author

TheOneTheOnlyJJ commented Aug 28, 2024

@TheOneTheOnlyJJ Why would this be needed? The core PasswordWidget works with MUI as it passes the correct prop to BaseInputTemplate, which then gets passed to MUI's TextField. See the playground with the MUI v5 theme. The password field already works.

I opened this issue thinking that a password widget must also allow you to show/hide the password one way or another, for example through a typical eye icon adornment at the edge of the input. However, given that this is not a standard feature of password inputs, your observation makes sense.

In my project, I wanted to be able to show/hide the password, and I've come up with this solution:

import IconButton from "@mui/material/IconButton/IconButton";
import InputAdornment from "@mui/material/InputAdornment/InputAdornment";
import useTheme from "@mui/material/styles/useTheme";
import TextField from "@mui/material/TextField/TextField";
import VisibilityIcon from "@mui/icons-material/Visibility";
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
import { WidgetProps } from "@rjsf/utils";
import { FocusEvent, ChangeEvent, FC, useState, useMemo } from "react";

const PasswordWidget: FC<WidgetProps> = (props: WidgetProps) => {
  const { id, required, disabled, readonly, options, rawErrors, onChange, onBlur, onFocus } = props;
  const _onChange = ({ target: { value } }: ChangeEvent<HTMLInputElement>): void => {
    onChange(value === "" ? options.emptyValue : value);
  };
  const _onBlur = ({ target }: FocusEvent<HTMLInputElement>): void => {
    onBlur(id, target.value);
  };
  const _onFocus = ({ target }: FocusEvent<HTMLInputElement>): void => {
    onFocus(id, target.value);
  };
  const [doShowPassword, setDoShowPassword] = useState<boolean>(false);

  const hasError: boolean = useMemo((): boolean => {
    return rawErrors !== undefined && rawErrors.length > 0;
  }, [rawErrors]);

  const theme = useTheme();

  const iconColor: string = useMemo((): string => {
    return hasError ? theme.palette.error.main : theme.palette.text.secondary;
  }, [theme, hasError]);

  return (
    <TextField
      id={id}
      type={doShowPassword ? "text" : "password"}
      label={props.schema.title ?? props.id}
      value={(props.value as string) || ""}
      required={required}
      disabled={disabled}
      onChange={_onChange}
      onBlur={_onBlur}
      onFocus={_onFocus}
      variant="outlined"
      fullWidth
      error={hasError}
      InputProps={{
        readOnly: readonly,
        endAdornment: (
          <InputAdornment position="end">
            <IconButton
              aria-label="toggle password visibility"
              onClick={(): void => {
                setDoShowPassword((prevShowPassword) => !prevShowPassword);
              }}
            >
              {doShowPassword ? <VisibilityIcon style={{ color: iconColor }} /> : <VisibilityOffIcon style={{ color: iconColor }} />}
            </IconButton>
          </InputAdornment>
        )
      }}
    />
  );
};

export default PasswordWidget;

This code was generated with ChatGPT-4o and then typed and polished manually by myself. I'm sure it could be polished even further, but it does its job. For anyone from the future looking for this, you can copy all of this into a new file and start using it directly in your UI Schemas. The Material UI version I used it with is 5.16.7. It might need tweaks if used with newer/older versions.

@glebcha
Copy link

glebcha commented Aug 30, 2024

@TheOneTheOnlyJJ Such custom password field can be implemented as custom widget.
I did nearly the same in my project.

@TheOneTheOnlyJJ
Copy link
Author

@TheOneTheOnlyJJ Such custom password field can be implemented as custom widget. I did nearly the same in my project.

Would you share your implementation here? This way, everyone stumbling upon this has a greater sample size of code to look at & add to their projects.

@glebcha
Copy link

glebcha commented Sep 4, 2024

@TheOneTheOnlyJJ Such custom password field can be implemented as custom widget. I did nearly the same in my project.

Would you share your implementation here? This way, everyone stumbling upon this has a greater sample size of code to look at & add to their projects.

There is shared example in discussions #4058

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting response feature Is a feature request
Projects
None yet
Development

No branches or pull requests

3 participants