Skip to content

Add more precise typing for autocomplete HTML attribute - #1467

Merged
github-actions[bot] merged 8 commits into
microsoft:mainfrom
yanndinendal:add_autocomplete_html_attribute
Jun 19, 2023
Merged

Add more precise typing for autocomplete HTML attribute#1467
github-actions[bot] merged 8 commits into
microsoft:mainfrom
yanndinendal:add_autocomplete_html_attribute

Conversation

@yanndinendal

@yanndinendal Yann Brelière (yanndinendal) commented Jan 9, 2023

Copy link
Copy Markdown
Contributor

This will allow to autocomplete… the autoComplete attribute in vscode for example.

autoComplete autocompletion in vscode

The list is quite long and it's not easy remembering the spelling of each one of them (first_name or given-name? password or current-password?), and it would improve the UX of sites if they were more appropriately used (for example, some people may think that the input's type and/or name attributes may be enough for fields like email or password, but knowing to use autoComplete="new-password" or one-time-code can be really useful).


I tried declaring a type AutoComplete to avoid repetition but didn't find how to do that:
microsoft/TypeScript#52169.

See updated proposal at #1467 (comment)

Fixes microsoft/TypeScript#52168.
See also #71.

@github-actions

github-actions Bot commented Jan 9, 2023

Copy link
Copy Markdown
Contributor

Thanks for the PR!

This section of the codebase is owned by Kagami Sascha Rosylight (@saschanaz) - if they write a comment saying "LGTM" then it will be merged.

@yanndinendal

Yann Brelière (yanndinendal) commented Jan 9, 2023

Copy link
Copy Markdown
Contributor Author

@microsoft-github-policy-service agree

@yanndinendal

Copy link
Copy Markdown
Contributor Author

@microsoft-github-policy-service agree

@saschanaz

Copy link
Copy Markdown
Contributor

First, please define an enum (which then generates a union type) and use that.

Second, are we sure every item here is well supported? Poorly supported items shouldn't be added.

@HolgerJeromin

Copy link
Copy Markdown
Contributor

Typescript team should be confident that they want (string & {}) in this repo which uses a side effect of current typescript intellisense code.
If yes, this should perhaps be done for all attributes instead of one (the data should be available afaik).

@orta

Copy link
Copy Markdown
Contributor

@yanndinendal

Yann Brelière (yanndinendal) commented Jan 10, 2023

Copy link
Copy Markdown
Contributor Author

Kagami Sascha Rosylight (@saschanaz): thanks, fixed (I didn't know how to do it with these json files, at first).

I've re-read the spec and declared an AutoFill enum that matches the spec, and I've tested most of them and confirmed they seem indeed supported in at least Chrome or Firefox.
I couldn't find definite info on Can I Use or MDN except for some of them like new-password which is largely supported:
https://caniuse.com/mdn-html_global_attributes_autocomplete_new-password

I've also fixed the possible values for autocomplete on a form element, which can't act as an autofill element, and confirmed it's supported on textareas and selects:


I added webauthn, which is in the spec (linked in the comments) and can be used in combination with username or current-password values (already available in stable releases of Chrome):
https://web.dev/passkey-form-autofill/


Unfortunately, I don't know how to add typescript auto-completion for a list of strings (space-separated tokens, like "username webauthn" or "shipping street-address"), but it should already cover most use-cases (and more advanced ones are handled with (string & {})).
Holger Jeromin (@HolgerJeromin): So it's necessary to keep it instead of a strict list to follow the spec (it also prevents this to be a breaking change).

Also note that this syntax/workaround is already used and tested in the TypeScript repo,
such as with tests/baselines/reference/specialIntersectionsInMappedTypes.types's
type Alignment = (string & {}) | "left" | "center" | "right";
or tests/lib/react18/react18.d.ts's AriaRole.

@saschanaz

Copy link
Copy Markdown
Contributor

What does (string & {}) do, why not just string?

It's also currently broken, please use AutoFill | string instead for overrideType.

@yanndinendal

Yann Brelière (yanndinendal) commented Jan 10, 2023

Copy link
Copy Markdown
Contributor Author

Kagami Sascha Rosylight (@saschanaz):

With | (string & {}):

autoComplete autocompletion in vscode

With | string:

no editor auto-completion at all.


See microsoft/TypeScript#33471, and microsoft/TypeScript#29729 for an explanation of the issue.

I think I originally stumbled on this method in React's typedefs.

@yanndinendal

Copy link
Copy Markdown
Contributor Author

It's also currently broken, please use AutoFill | string instead for overrideType.

Kagami Sascha Rosylight (@saschanaz): Sorry I don't understand that last part, the tests pass and it seems to work.
By broken, do you mean that it should generate something else? Or that some cases (not handled by the tests) will not work?

I can't use | string or we will lose autocompletion (it would have type string only).

@saschanaz

Copy link
Copy Markdown
Contributor

Look at the output: type AutoFill = "(string & {})". You don't want this 😛

@yanndinendal

Yann Brelière (yanndinendal) commented Jan 10, 2023

Copy link
Copy Markdown
Contributor Author
(wrong obsolete comment)

Do you see the right commit? I see the full union:

image

@yanndinendal

Yann Brelière (yanndinendal) commented Jan 10, 2023

Copy link
Copy Markdown
Contributor Author

Sorry I got it, the rest of the union is ok but "(string & {})" should not be quoted :o

I don't know how to do that :/ fixed

@RyanCavanaugh

Copy link
Copy Markdown
Member

Do not add string & {} to this file.

If the set of values is truly unconstrained, string is the appropriate type, and is what should be written here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per prior comment

@saschanaz

Copy link
Copy Markdown
Contributor

Yup, that's also what other properties do.

@yanndinendal

Yann Brelière (yanndinendal) commented Jan 11, 2023

Copy link
Copy Markdown
Contributor Author

If the set of values is truly unconstrained, string is the appropriate type, and is what should be written here.

It's not unconstrained. Writing string or any union | string wold lose any auto-completion, so we might as well close this PR if that's not something you want. Can I ask why?

I could try writing it as a string template literal type instead, based on this table from the spec, to allow 1, 2, 3 or 4 tokens from the union, in the correct order, but it would take me some time to do it right so we may want to first discuss if this could be investigated/accepted, or if it wouldn't be accepted either.

@yanndinendal

Yann Brelière (yanndinendal) commented Jan 11, 2023

Copy link
Copy Markdown
Contributor Author

Typescript team should be confident that they want (string & {}) in this repo which uses a side effect of current typescript intellisense code.

just to clarify that this is to work around a bug in typescript; I would be happy to use | string instead once it's fixed, but in the meanwhile it would be no better than closing this PR and losing type suggestions.

See issues linked in #issuecomment-1377304118 for explanations.

@yanndinendal

Copy link
Copy Markdown
Contributor Author

Re #issuecomment-1378404272

I could try writing it as a string template literal type instead, based on this table from the spec, to allow 1, 2, 3 or 4 tokens from the union, in the correct order

Here are the full constraints, in the right order, for the set of space-separated tokens:

- `section-${string}`
- "shipping" | "billing"
- AutoFill // (the union I added to this PR, excluding "webauthn")
- "webauthn"

@yanndinendal

Yann Brelière (yanndinendal) commented Jan 11, 2023

Copy link
Copy Markdown
Contributor Author

Kagami Sascha Rosylight (@saschanaz), Ryan Cavanaugh (@RyanCavanaugh): Ok, here is how it would look like, it should be restricted to all authorized permutations (because for Autofill detail tokens (all except on/off), the autofill field names union is the only mandatory token of the list).
I will need to declare these types in this repo's json files but I made it work locally with a standard .d.ts file and it's quite impressive what it can suggest!

  type AutoFillSection = `section-${string}`;
  type AutoFillAddressKind = 'shipping' | 'billing';
  type AutoFillNormalField =
    | 'name'
    | 'honorific-prefix'
    | 'given-name'
    | 'additional-name'
    | 'family-name'
    | 'honorific-suffix'
    | 'nickname'
    | 'username'
    | 'new-password'
    | 'current-password'
    | 'one-time-code'
    | 'organization-title'
    | 'organization'
    | 'street-address'
    | 'address-line1'
    | 'address-line2'
    | 'address-line3'
    | 'address-level4'
    | 'address-level3'
    | 'address-level2'
    | 'address-level1'
    | 'country'
    | 'country-name'
    | 'postal-code'
    | 'cc-name'
    | 'cc-given-name'
    | 'cc-additional-name'
    | 'cc-family-name'
    | 'cc-number'
    | 'cc-exp'
    | 'cc-exp-month'
    | 'cc-exp-year'
    | 'cc-csc'
    | 'cc-type'
    | 'transaction-currency'
    | 'transaction-amount'
    | 'language'
    | 'bday'
    | 'bday-day'
    | 'bday-month'
    | 'bday-year'
    | 'sex'
    | 'url'
    | 'photo';
  type AutoFillContactKind = 'home' | 'work' | 'mobile' | 'fax' | 'pager';
  type AutoFillContactField =
    | 'tel'
    | 'tel-country-code'
    | 'tel-national'
    | 'tel-area-code'
    | 'tel-local'
    | 'tel-local-prefix'
    | 'tel-local-suffix'
    | 'tel-extension'
    | 'email'
    | 'impp';
  type AutoFillField =
    | AutoFillNormalField
    | AutoFillContactField
    | `${AutoFillContactKind} ${AutoFillContactField}`;
  type AutoFillCredentialField = 'webauthn';

  type AutoFill =
    | 'off'
    | 'on'
    | AutoFillField
    | `${AutoFillSection} ${AutoFillField}`
    | `${AutoFillAddressKind} ${AutoFillField}`
    | `${AutoFillSection} ${AutoFillAddressKind} ${AutoFillField}`
    | `${AutoFillSection} ${AutoFillAddressKind} ${AutoFillField} ${AutoFillCredentialField}`
    | `${AutoFillAddressKind} ${AutoFillField} ${AutoFillCredentialField}`
    | `${AutoFillSection} ${AutoFillField} ${AutoFillCredentialField}`
    | `${AutoFillField} ${AutoFillCredentialField}`;

Here are example suggestions and valid strings:

  • even the space-separated "contact kind + contact field" template string are suggested, with all possible permutations:
    contact kind + contact field template string type autocompletion
  • only section- isn't auto-completed (but is typed/validated):
    section non-autocompletion
  • typed section-*:
    valid string with section-* and valid space-separated unions
  • invalid string with missing mandatory AutoFillField:
    invalid string example
  • other autocompleted valid strings with several categories:
    webauthn-autocompletion
    valid string with webauthn
  • still works for trivial values:
    one-word example
    on/off values
  • invalid example:
    off + other token

@HolgerJeromin

Copy link
Copy Markdown
Contributor

Also note that this syntax/workaround is already used and tested in the TypeScript repo,
such as with tests/baselines/reference/specialIntersectionsInMappedTypes.types's
type Alignment = (string & {}) | "left" | "center" | "right";
or tests/lib/react18/react18.d.ts's AriaRole.

Internal tests are different from code which is shipped to many developers and shapes the way they work.

@yanndinendal

Yann Brelière (yanndinendal) commented Jan 11, 2023

Copy link
Copy Markdown
Contributor Author

Holger Jeromin (@HolgerJeromin): Right. Does the above proposition sound better than the first one? With template string types?

@yanndinendal
Yann Brelière (yanndinendal) force-pushed the add_autocomplete_html_attribute branch 2 times, most recently from 2f40faa to ca386d5 Compare January 21, 2023 00:39
@yanndinendal

Copy link
Copy Markdown
Contributor Author

Hi Ryan Cavanaugh (@RyanCavanaugh), Kagami Sascha Rosylight (@saschanaz): I pushed a new version without | (string & {}) that is now fully spec-compliant. I would appreciate any feedback. :)

See #1467 (comment) for screenshots and context.

@yanndinendal
Yann Brelière (yanndinendal) marked this pull request as draft January 24, 2023 08:43
@yanndinendal
Yann Brelière (yanndinendal) force-pushed the add_autocomplete_html_attribute branch from d3cb416 to b3466ed Compare June 19, 2023 14:02
@yanndinendal

Copy link
Copy Markdown
Contributor Author

Edit: WPT wpt.fyi/results/html/semantics/forms/the-form-element/form-autocomplete.html?label=master&label=experimental&aligned&q=autocomplete

Kagami Sascha Rosylight (@saschanaz) So looks like everything is good on that page, right?

The only tests that fail on two browsers are with one-time-code, but it's clearly supported by iOS Safari: https://developer.apple.com/documentation/security/password_autofill/enabling_password_autofill_on_an_html_input_element
and webauthn with a combination of everything else (section, mode, contact, field, and credential), which is probably an unexpected limitation (webauthn alone is supported; other combinations are supported), so there is no reason to add arbitrary restrictions to type definitions for this.

I've rebased, is it ready to merge? :)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the long delay, and thank you for maintaining this so far!

Looks good with some nits. It seems a bit more fields are supported now than this was written, but asking that change here would be very unfair, that can be done separately.

},
{
"name": "AutoFillSection",
"overrideType": "`section-${string}`"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a TODO comment about the over-match of section-{string}?

Comment thread unittests/files/autocomplete.ts Outdated
Comment thread inputfiles/addedTypes.jsonc
@saschanaz

Copy link
Copy Markdown
Contributor

I'm assuming that having the Optional*Token helper types here is okay, as Nathan Shively-Sanders (@sandersn) hasn't complained about that.

@yanndinendal

Copy link
Copy Markdown
Contributor Author

Kagami Sascha Rosylight (@saschanaz): pushed, thanks! :)

@saschanaz

Copy link
Copy Markdown
Contributor

Let's see I can merge this even if there's a change request, because that's solved now.

LGTM

@github-actions
github-actions Bot merged commit dbf56b1 into microsoft:main Jun 19, 2023
@github-actions

Copy link
Copy Markdown
Contributor

Merging because Kagami Sascha Rosylight (@saschanaz) is a code-owner of all the changes - thanks!

@yanndinendal
Yann Brelière (yanndinendal) deleted the add_autocomplete_html_attribute branch June 19, 2023 18:14
@yanndinendal

Copy link
Copy Markdown
Contributor Author

@saschanaz

Copy link
Copy Markdown
Contributor

(I'm not really allowed to know such info, but the roadmap implies the new release is coming soonish, as the release happens roughly every three months and the last release was three months ago.) https://github.com/microsoft/TypeScript/wiki/Roadmap)

@saschanaz

Kagami Sascha Rosylight (saschanaz) commented Jun 20, 2023

Copy link
Copy Markdown
Contributor

If you need it today, consider using https://www.npmjs.com/package/@types/web.

... except it looks like the release step is broken since 0.0.99. (Edit: Filed #1580)

@sandersn

Nathan Shively-Sanders (sandersn) commented Jun 20, 2023

Copy link
Copy Markdown
Member

I'm assuming that having the Optional*Token helper types here is okay, as Nathan Shively-Sanders (@sandersn) hasn't complained about that.
Basically yes. I'll check the performance numbers when I copy the types into TS 5.2 beta tomorrow but I think it'll be OK.

I'll check out the publication failure and try to fix it.

Edit: Oh, looks you have a potential fix already. I'll merge that.

@yanndinendal

Yann Brelière (yanndinendal) commented Oct 9, 2023

Copy link
Copy Markdown
Contributor Author

Unfortunately, this does not get picked up by @types/react / @types/react-dom JSX autoComplete prop. ¯\_(ツ)_/¯

Asking for instructions here: DefinitelyTyped/DefinitelyTyped#66982

@gavinwahl

Copy link
Copy Markdown

I think this type is too strict. All the tokens should be matched case-insensitively, so autoComplete="NeW-PASSworD" needs to be allowed.

https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-detail-tokens

a token that is an ASCII case-insensitive match for one of the following strings:
...

@HolgerJeromin

Copy link
Copy Markdown
Contributor

I think this type is too strict. All the tokens should be matched case-insensitively, so autoComplete="NeW-PASSworD" needs to be allowed.

In general typescript does not allow all valid and spec'ed code but try to give hints to best practice while still being useful.
Most setters designed for strings in browser APIs allows for example any content which will be converted to string internally.
Still TS forces the string datatype.

I think this is a similar (but less strong) decision.

Beside the point that typescript IMO does not have the concept for string types needed here.

@saschanaz

Copy link
Copy Markdown
Contributor

Indeed, there's no case-insensitive string type.

@gavinwahl

Copy link
Copy Markdown

I think string is the only reasonable option here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve HTML autocomplete attribute

8 participants