It might be possible to use something along the lines of
xargs -n1 -I[] sh -c 'cat {} | grep foo > {}.foo'
or, to get rid of the useless cat
xargs -n1 -I{} sh -c 'grep foo {} > ().foo'
It's usually easier to put it in a shell script so you can just pass it files.
cat > fiddle.sh <<\EOF
for f in "$@"; do
grep foo "$f" >"$f.foo"
done
EOF
ls *.txt | xargs sh fiddle.sh # note we can now pass multiple files, no -n1 or -I needed
Pedantry: ls won't do the right thing with special characters, notably embedded newlines, in filenames. I'd dump the xargs entirely, and (given the above script) just do
sh fiddle.sh *.txt
or even
for f in *.txt; do grep foo "$f" >"$f.txt"; done
right at the prompt.