[BUG] Plugin Input empties on Enter while the hook still draws the same value
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
In a function-hooks plugin, an Input shows an empty field after Enter, although the hook keeps drawing the same value and onSubmit got the text. The next key then calls onInput with that one character, so the text the plugin held is replaced.
InputProps.value is documented as "the text the field holds when drawn; the person's typing replaces it until the hook draws another". Nothing there says Enter clears it.
I hit this in a mod's search field: after Enter the filter stays applied, the field looks empty, and the next key starts a new search.
What Should Happen?
After Enter the field shows the value the hook draws (abc), and typing d gives abcd. If clearing on submit is intended, the docs should say so; a hook that wants an empty field can draw value="".
Error Messages/Logs
None. What the pane shows at each step (the second line is the hook's own value and submit count):
after typing abc │ abc ⏎ submit
│ value prop drawn: "abc" · submits: 0
after Enter │ ⏎ submit
│ value prop drawn: "abc" · submits: 1
after typing d │ d ⏎ submit
│ value prop drawn: "d" · submits: 1
Steps to Reproduce
- Make a plugin folder
input-probewith these three files.
.claude-plugin/plugin.json:
{ "name": "input-probe", "version": "0.0.0", "description": "Input value after Enter" }
hooks/hooks.json:
{ "modules": ["./register.tsx"] }
hooks/register.tsx:
export const register = on => {
let value = ''
let submits = 0
on('session.start', async ($, e, next) => {
await $.command.register({ name: 'probe', description: 'Open the Input probe' })
return next(e)
})
on('command.run', { command: 'probe' }, async $ => {
await $.ui.open({ id: 'probe', title: 'probe', focus: true, closeOnEscape: true })
return { text: '' }
})
on('ui.render', { component: 'Pane', requestId: 'probe' }, ($, e) => {
const { Box, Text, Input } = $.ui.resolve(e)
return (
<Box flexDirection="column">
<Input
key="field"
autoFocus
value={value}
onInput={text => { value = text; $.ui.invalidate('ui.render') }}
onSubmit={text => { value = text; submits += 1; $.ui.invalidate('ui.render') }}
/>
<Text>{`value prop drawn: "${value}" · submits: ${submits}`}</Text>
</Box>
)
})
}
claude --plugin-dir ./input-probe(claude plugin validate ./input-probepasses).- Run
/probe. The pane opens with the field focused. - Type
abc. The line under the field saysvalue prop drawn: "abc" · submits: 0. - Press Enter. The field is empty; the line says
value prop drawn: "abc" · submits: 1. - Type
d. The field showsdand the line saysvalue prop drawn: "d".
Claude Model
_No response_
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.296 (Claude Code)
Platform
Anthropic API
Operating System
Other Linux
Terminal/Shell
Other
Additional Information
Arch Linux (kernel 7.2.9), kitty 0.49.2, inside herdr 0.9.3; I first saw it in kitty alone. The probe needs no login: it reproduces in a fresh CLAUDE_CONFIG_DIR before signing in.