[BUG] <sp-textfield/> selects first character after `invalid` state changes

On first render I have empty <sp-textfield/>. I start typing and all seems fine. Then I delete text in the field, invalid state changes, input turns red. Then, when I start typing again, first character is lost, because it always gets selected after it’s typed

    const isFirstRender = useRef(true)
    const [error, setError] = useState(false)
    const [title, setTitle] = useState("")

    useEffect(() => {
        if (isFirstRender.current) {
            isFirstRender.current = false

            return
        }

        setError(!title)
    }, [title]);

    return (
        <sp-textfield
            invalid={error ? true : null}
            onInput={(e) => setTitle(e.target.value.trim())}
            value={title}
        >
            <sp-label isrequired={true} slot="label">Title</sp-label>
        </sp-textfield>
    )

No issue if there’s no invalid attribute at all or it never changes (can be true on first render)

3.5 years… Anything? I just got a client complaining about this issue :disappointed:

We’re looking forward to the next version of PS having a submenu: Plugins > Legacy2 > UXP… your plugins.

And the joyful news that: “Guys, we’re bringing back Chromium and Node.js, and xbytor is becoming the lead of the development team. We’ll come up with a name for the new platform later.” That would be awesome!

Does it happen in swc as well? Btw shouldn’t be label parent of textfield?

According to examples in the docs, no :confused:


Didn’t test now. At the time SWC was not available and now it would be lots of work to change everywhere :frowning:

I wouldn’t believe adobe uxp docs. Check mdn <label>: The Label element - HTML: HyperText Markup Language | MDN their example has label as parent.

I’ll need check that. But then there’s no point to have a slot at all and I guess it would misalign the UI from the default Ps UI recommendations. I want my plugin forms to look as close as possible to Ps UI and adapt if Adobe decides to make changes :frowning:

But that also means if Adobe makes a changes it can break your UI automatically. I remember sp-checkbox with different vertical padding in each PS version :smiley:

In such case it’s at least clear who’s fault it is :sweat_smile:

Oh, BTW, if I remember it right, it’s now a second time I’ve got this from the review team after plugin submission

Greetings from the Adobe Creative Cloud Integrations Review Team. We are writing to you about your plugin below:

Plugin ID: e0ff91d5
Plugin name: Custom Panel Lite

Hi Team, During the review of your “Custom Panel Lite” plugin we observed that while typing in the search text box, the first letter is automatically selected by default. Consequently, when the second letter is typed, it deletes the first letter. As a one time exception we are approving this plugin , kindly fix the issue and submit a patch.

Thank you,
The Creative Cloud Integrations Review Team

I’m sure at some point submission will be completely rejected because of Adobes own bugs. I’m thinking now maybe it’s worth pinging @Erin_Finnegan to forward this to the appropriate team

Also I see exact same behaviour on other UXP plugins, not just mine

@Karmalakas When a validation error occurs, UXP needs to refresh textfields to display the invalid icon. This refresh causes two problems:

  1. The textfield loses focus
  2. When focus returns, all text becomes selected

This selection behavior is a default textfield characteristic in hosts and we cannot modify. When a user begins typing with text selected, their new input replaces all existing text—often resulting in the frustrating loss of their previous entry, in this case specifically the first letter.

As a temporary solution, I would suggest a workaround that:

  • Detects when a textfield recovers from an invalid state
  • Captures the text the user is typing
  • Automatically reappends it to preserve their input

While this approach is unconventional, it effectively prevents the text loss issue until a more elegant solution becomes available.

const [error, setError] = useState(false);
  const [title, setTitle] = useState("");
  const [cachedText, setCachedText] = useState("");
  const [appendText, setAppendText] = useState(false);
  
  const handleInput = (e) => {
    const inputValue = e.target.value.trim();
    
    if (inputValue === "") {
      setError(true);
    } else if (error) {
      // When recovering from invalid state
      setError(false);
      setCachedText(inputValue);
      setAppendText(true);
      return;
    }
    
    // Apply appended text if needed
    if (appendText) {
      setTitle(cachedText + inputValue);
      setAppendText(false);
    } else {
      setTitle(inputValue);
    }
  };
  
  return (
    <sp-textfield 
      invalid={error ? true : null} 
      onInput={handleInput}
      value={title}
    >
      <sp-label isrequired={true} slot="label">Title</sp-label>
    </sp-textfield>
  );

Why? This is clearly a UXP/host bug. Why not fix it in the core? Why suggest to developers to complicate their code?

I’m sorry, but for now I have more important work to do on my plugins. And all my plugins are already full of workarounds because of similar bugs, so I’m not adding another one, especially when it’s a non-breaking. I just keep sending links to topics here to Adobe review team and my users when they say something is glitchy and there’s an open bug already. And it’s not the only similar case when UI bugs aren’t addressed for years.. That’s even more frustrating, than disappearing first character :disappointed_face:

We recognize the inconvenience this causes but what you are running into here is behavior that is by design and this was the desired behavior by all internal Adobe plugins. It’s manifesting in this state, so we are only able to offer a workaround for now. Adding @samgannaway in case he might want to add on the default design here.

I would really love to know the reasoning behind such decision. Maybe I’m missing something, but without more info this doesn’t make any sense to me why would anyone want a bug by design :face_with_monocle:

Text input widget in UXP is garbage very problematic. There are like 50-100 issues with it. It is some sort of C++ made UI overlay above the panel… therefore infinite z-index.

It would be great if there could be same text input as in real webbrowsers so it would behave in same way and be actually part of the HTML layout instead being rendered additionally above.

Textarea could have scrollbar on windows, scrollbar would not have z-index infinity and beyond. I could style it and e.g. change font or its size.

I think it could be better to make hybrid plugin capable of starting server and then use Webview for plugins UI. It could save days/weeks of development time. All CSS features supported, and proper canvas, full HTML DOM. npm modules and design systems working at first try without hacking.

You would not be able to publish on Marketplace… but considering its capabilities e.g. not able to make custom discount codes without sending e-mail or seeing customer details e.g. e-mail …it might be better to publish elsewhere anyway.

2 Likes

That’s the blocker for me :frowning: I’ve no idea how to do it and no time to research. AT least not yet.

I was able to do nice features in hybrid plugin with help of ChatGPT. C++ is well known for decades… plenty of examples. You are not going to ask for revolutionary code. It only needs to generate some glue for open sourced libraries made by someone else. UXP uses same NAPI as NodeJS… that should help as well. I also bough Davide book and tried some code samples to adjust.

1 Like

BTW, @Majji, your suggested workaround also doesn’t really work. Consider these steps:

  • Start typing “photoshop”
  • Realize you wanted first uppercase
  • Delete everything and get error
  • Want to type P, but a mistake is made and you type O
  • You don’t want it to be Ohotodhop and you try to fix it
  • Re-select that mistyped O
  • Start typing Photo....
  • You end up with OPhoto...

Honestly, I didn’t test it practically, but that’s what I get from the code and video