# TextField (w-textfield)

## Description

A single-line input component used for entering and editing textual or numeric data.

[Warp component reference](https://warp-ds.github.io/docs/components/text-area/frameworks/elements)

## Usage

<elements-example>
    
```html
<w-textfield label="Email" type="email"></w-textfield>
```

</elements-example>

### Validation

Set the `invalid` attribute to display a textfield as invalid.

`invalid` should be paired with `help-text` to provide feedback to the user about how to correct the error.

<elements-example>

```html
<w-textfield 
    label="Email"
    invalid
    help-text="An email should have an @ sign and a domain name, for example ola.nordmann@finn.no"
></w-textfield>
```

</elements-example>

## Accessibility

If a visible label isn't specified, an `aria-label` must be provided to the text field for accessibility. If the field is labeled by a separate element, an `aria-labelledby` property must be provided using the `id` of the labeling element instead.

- Always provide a visible label (do not rely on `placeholder` alone).
- Do not rely on color alone for interaction feedback (e.g. error states).
- Interaction patterns should follow platform-native expectations (e.g. tap zones, keyboard navigation, etc) and must not block accessibility tools.

### When used with an affix

When `search` or `clear` set on the [affix](#with-affix) component it renders a button and a default `aria-label`. If the `aria-label` incorrect for your context, you may provide your own describing the action.

```html
<w-affix search aria-label="Ad Search"></w-affix>
<w-affix clear aria-label="Clear text input"></w-affix>
```

## Examples

### Placeholder

Placeholder text can be used to describe the expected value or formatting for the textfield.

Placeholder text will only appear when the textfield is empty, and must not be used as a
substitute for labeling the element with a visible label.

<elements-example>
    
```html
<w-textfield label="Email" placeholder="ola.nordmann@finn.no"></w-textfield>
```

</elements-example>

### Prefix label

<elements-example>

```html
<w-textfield label="Price">
  <w-affix slot="prefix" label="kr"></w-affix>
</w-textfield>
```

</elements-example>

### Suffix Label

<elements-example>
  
```html
<w-textfield label="Price">
  <w-affix slot="suffix" label="kr"></w-affix>
</w-textfield>
```

</elements-example>

### Prefix Search Icon

<elements-example>
  
```html
<w-textfield label="Search">
  <w-affix slot="prefix" search></w-affix>
</w-textfield>
```

</elements-example>

### Suffix Search Icon

If you wrap the textfield with affix in a form element, clicking the search button will automatically submit the form

<elements-example>

```html
<form>
  <w-textfield label="Search">
    <w-affix slot="prefix" search></w-affix>
  </w-textfield>
</form>
```

</elements-example>

### Suffix Clear Icon

Clicking the clear button will reset the textfield

<elements-example>

```html
<w-textfield label="Search input">
  <w-affix slot="suffix" clear></w-affix>
</w-textfield>
```

</elements-example>

### Affix with arbitrary icon

<elements-example>
  
```html
<w-textfield label="Award">
  <w-affix slot="prefix" icon="AwardMedal"></w-affix>
</w-textfield>
```

</elements-example>

### Disabled

Keep in mind that using disabled in its current form is an anti-pattern.

There will always be users who don't understand why an element is disabled, or users who can't even see that
it is disabled because of poor lighting conditions or other reasons.

Please consider more informative alternatives before choosing to use disabled on an element.

<elements-example>
    
```html
<div class="flex flex-col space-y-32">
  <w-textfield label="Email" disabled value="ola.nordmann@finn.no"></w-textfield>
  <w-textfield label="Email" disabled></w-textfield>
</div>
```

</elements-example>

### Read only

The readonly boolean attribute makes the w-textfield's text content immutable. Unlike disabled the w-textfield remains focusable and the contents can still be copied. See [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/readOnly) for more information.

<elements-example>

```html
<w-textfield 
  label="Email" 
  type="email" 
  value="ola.nordmann@finn.no" 
  readonly
></w-textfield>
```

</elements-example>

## Styling API

This section documents the supported styling hooks for `<w-textfield>`.

Use these hooks to customize appearance without relying on internal structure or selectors.

Before changing the default styles, remember that doing so can result in less consistent experiences for users across the product. Prefer defaults.

- Prefer **component tokens** for size, spacing, and state styling.
- Use **parts** only for small, local tweaks.
- Avoid relying on internal class names or selectors.

### Parts

The textfield exposes a minimal set of parts that can be targeted for last‑mile layout or typography tweaks.

| Part | Targets | Typical use |
|---|---|---|
| `input` | native input element | minor typography or spacing tweaks |

Example:

```css
w-textfield::part(input) {
  letter-spacing: 0.5px;
}
```

Parts are intended as an **escape hatch**.
Prefer component tokens for anything state‑ or size‑related.


### Component tokens

Component tokens (`--w-c-input-*`) act as inputs to the textfield styling.
They can be set directly on the component or inherited from a parent container.

These tokens are **shared across textfield, textarea, and select** for consistent form styling.

```css
.form-section {
  --w-c-input-label-font-weight: 600;
  --w-c-input-help-text-color: var(--w-s-color-text);
}
```

Defaults are defined internally; setting a token is always optional.


#### Label tokens

| Token | Purpose | Default |
|---|---|---|
| `--w-c-input-label-color` | label text color | `--w-s-color-text` |
| `--w-c-input-label-font-size` | label font size | `--w-font-size-s` |
| `--w-c-input-label-line-height` | label line height | `--w-line-height-s` |
| `--w-c-input-label-font-weight` | label font weight | `700` |
| `--w-c-input-label-padding-bottom` | space below label | `0.4rem` |
| `--w-c-input-label-cursor` | cursor when hovering label | `pointer` |
| `--w-c-input-label-display` | label display mode | `block` |


#### Optional indicator tokens

When `optional` attribute is set, these tokens control the "(optional)" text styling:

| Token | Purpose | Default |
|---|---|---|
| `--w-c-input-optional-color` | optional text color | `--w-s-color-text-subtle` |
| `--w-c-input-optional-font-size` | optional text font size | `--w-font-size-s` |
| `--w-c-input-optional-line-height` | optional text line height | `--w-line-height-s` |
| `--w-c-input-optional-font-weight` | optional text font weight | `400` |
| `--w-c-input-optional-padding-left` | space before optional text | `0.8rem` |


#### Help text tokens

| Token | Purpose | Default |
|---|---|---|
| `--w-c-input-help-text-color` | help text color (normal state) | `--w-s-color-text-subtle` |
| `--w-c-input-help-text-color-invalid` | help text color when invalid | `--w-s-color-text-negative` |
| `--w-c-input-help-text-font-size` | help text font size | `--w-font-size-xs` |
| `--w-c-input-help-text-line-height` | help text line height | `--w-line-height-xs` |
| `--w-c-input-help-text-margin-top` | space above help text | `0.4rem` |
| `--w-c-input-help-text-display` | help text display mode | `block` |


## Implementation notes

### Shared token system

Textfield shares its label, optional indicator, and help text tokens with `w-textarea` and `w-select`. This ensures consistent form styling across all text input components.

### Affix accessibility

Due to shadow DOM boundaries, affix content (prefix/suffix slots) cannot be connected to the input via ARIA references. For non-interactive affixes like currency symbols or unit labels, consider including that information in the main `label` or `placeholder` text instead for better screen reader support.

## `<w-textfield>` API

Unless otherwise noted all properties are HTML attributes (as opposed to JavaScript object properties).

### Properties

| Name | Type | Default | Summary |
|-|-|-|-|
| autocomplete | `HTMLInputElement["autocomplete"] \| undefined` | `-` | A space-separated string that hints to browsers [what type of content it can suggest](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/autocomplete#value) to autofill. |
| disabled | `boolean` | `false` | Makes the element not focusable and hides it from form submits |
| formatter (JS only) | `((value: string) => string) \| undefined` | `-` | Function to format value when the input field |
| handler (JS only) | `handler(e: Event) => void` | `-` | - |
| help-text | `string \| undefined` | `-` | Description shown below the input field |
| invalid | `boolean` | `false` | Mark the form field as invalid. |
| label | `string \| undefined` | `-` | Either a `label` or an `aria-label` must be provided. |
| max | `number \| undefined` | `-` | Use with `type="number"` to set the [maximum allowed value](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#maxlength). |
| max-length | `number \| undefined` | `-` | **Deprecated**: Use the native `maxlength` attribute |
| maxlength | `number \| undefined` | `-` | For `text`, `search`, `url`, `tel`, `email` and `password` fields, sets the [maximum string length](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#maxlength) allowed. |
| min | `number \| undefined` | `-` | Use with `type="number"` to set the [minimum allowed value](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#minlength). |
| min-length | `number \| undefined` | `-` | **Deprecated**: Use the native `minlength` attribute |
| minlength | `number \| undefined` | `-` | For `text`, `search`, `url`, `tel`, `email` and `password` fields, sets the [minimum string length](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#minlength) required. |
| name | `string \| undefined` | `-` | The [name](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#name) of the input field when submitting the form. |
| optional | `boolean` | `false` | Whether to show the optional indicator after the label. |
| pattern | `string \| undefined` | `-` | Sets a [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions) that the input's value must [match to pass validation](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#pattern) |
| placeholder | `string \| undefined` | `-` | Shown in the textfield when it doesn't have a value |
| prefixSlotChange (JS only) | `prefixSlotChange() => void` | `-` | - |
| read-only | `boolean` | `false` | **Deprecated**: Use the native readonly attribute instead. |
| readonly | `boolean` | `false` | Whether the input can be selected but not changed by the user. |
| required | `boolean` | `false` | Whether user input is required on the input before form submission. |
| resetFormControl (JS only) | `resetFormControl() => void` | `-` | - |
| size | `string \| undefined` | `-` | Sets the [size](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#size) (width) of the input field to fit the expected length of inputs. |
| step | `number \| undefined` | `-` | Forces `number` inputs to be a whole number of `step` |
| suffixSlotChange (JS only) | `suffixSlotChange() => void` | `-` | - |
| type | `string \| undefined` | `-` | The [type of input](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#input_types). |
| value | `string \| undefined` | `-` | Lets you set the current value. |

### Property Details

#### autocomplete

A space-separated string that hints to browsers [what type of content it can suggest](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/autocomplete#value) to autofill.

- Type: `HTMLInputElement["autocomplete"] | undefined`
- Default: `-`

#### disabled

Keep in mind that using disabled in its current form is an anti-pattern.

There will always be users who don't understand why an element is disabled, or users who can't even see that it is disabled because of poor lighting conditions or other reasons.

Please consider more informative alternatives before choosing to use disabled on an element.

- Type: `boolean`
- Default: `false`

#### formatter (JS only)

Function to format value when the input field.

Only active when the input field does not have focus,
similar to the accessible input [masking example from Filament Group](https://filamentgroup.github.io/politespace/demo/demo.html).

- Type: `((value: string) => string) | undefined`
- Default: `-`

#### handler (JS only)



- Type: `handler(e: Event) => void`
- Default: `-`

#### help-text

Use in combination with `invalid` to show as a validation error message,
or on its own to show a help text.

- Type: `string | undefined`
- Default: `-`

#### invalid

Mark the form field as invalid. Make sure to also set a `help-text` to help users fix the validation problem.

- Type: `boolean`
- Default: `false`

#### label

Either a `label` or an `aria-label` must be provided.

- Type: `string | undefined`
- Default: `-`

#### max

Use with `type="number"` to set the [maximum allowed value](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#maxlength).

- Type: `number | undefined`
- Default: `-`

#### max-length

**Deprecated**: Use the native `maxlength` attribute



- Type: `number | undefined`
- Default: `-`

#### maxlength

For `text`, `search`, `url`, `tel`, `email` and `password` fields, sets the [maximum string length](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#maxlength) allowed.

- Type: `number | undefined`
- Default: `-`

#### min

Use with `type="number"` to set the [minimum allowed value](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#minlength).

- Type: `number | undefined`
- Default: `-`

#### min-length

**Deprecated**: Use the native `minlength` attribute



- Type: `number | undefined`
- Default: `-`

#### minlength

For `text`, `search`, `url`, `tel`, `email` and `password` fields, sets the [minimum string length](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#minlength) required.

- Type: `number | undefined`
- Default: `-`

#### name

The [name](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#name) of the input field when submitting the form.

- Type: `string | undefined`
- Default: `-`

#### optional

Whether to show the optional indicator after the label.

- Type: `boolean`
- Default: `false`

#### pattern

Sets a [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions) that the input's value must [match to pass validation](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#pattern)

- Type: `string | undefined`
- Default: `-`

#### placeholder

Set a text that is shown in the textfield when it doesn't have a value.

Placeholder text should not be used as a substitute for labeling the element with a visible label.

- Type: `string | undefined`
- Default: `-`

#### prefixSlotChange (JS only)



- Type: `prefixSlotChange() => void`
- Default: `-`

#### read-only

**Deprecated**: Use the native readonly attribute instead.



- Type: `boolean`
- Default: `false`

#### readonly

Whether the input can be selected but not changed by the user.

- Type: `boolean`
- Default: `false`

#### required

Whether user input is required on the input before form submission.

- Type: `boolean`
- Default: `false`

#### resetFormControl (JS only)



- Type: `resetFormControl() => void`
- Default: `-`

#### size

Sets the [size](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#size) (width) of the input field to fit the expected length of inputs.

- Type: `string | undefined`
- Default: `-`

#### step

When used with `number` this attribute forces inputs to be a whole number of `step`.

For example with a `step="5"` only values that divide evenly on 5 are allowed.
Using arrow up and down in the input field increments and decrements by 5.

- Type: `number | undefined`
- Default: `-`

#### suffixSlotChange (JS only)



- Type: `suffixSlotChange() => void`
- Default: `-`

#### type

The [type of input](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#input_types).

- Type: `string | undefined`
- Default: `-`

#### value

Lets you set the current value.

- Type: `string | undefined`
- Default: `-`

