# characterCount

> Why JS: a field's length changes with every keystroke and HTML has no live count, so script redraws a `CharacterCount`'s ring and number as the field is typed in.

```ts
import { characterCount } from "@sdxc/ui/mixins";
```

Applied to a `CharacterCount`'s host: follows the field named by `for`, and on every
input sets the host's `data-state` and `--ui-character-count-progress`, writes the number
left into `[data-character-count-number]`, and announces a change of state only, so a screen
reader hears "20 characters left" once rather than at every key.

## Signature

```ts
characterCount(options: CharacterCountSync.Options): MixinDescriptor<HTMLElement>
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `options` | `CharacterCountSync.Options` |  |

## Examples

```tsx
<span mix={[characterCount({ for: "draft", max: 280, warn: 20, holdSubmit: true, labels })]} />
```

## Used with it

The events, constants and types its module publishes, each imported from `@sdxc/ui/mixins` too.

### countCharacters

Counts what a reader sees as characters: grapheme clusters, so an emoji with skin tone or a
flag counts once. A server checking the same limit calls this, so the two never disagree.

#### Signature

```ts
countCharacters(text: string): number
```

Returns: Its length in user-perceived characters.

#### Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `text` | `string` | The field's text. |

### characterCountState

Places a length against its limit.

#### Signature

```ts
characterCountState(length: number, max: number, warn: number): CharacterCountState
```

Returns: The state the count draws.

#### Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `length` | `number` | The characters typed. |
| `max` | `number` | The limit. |
| `warn` | `number` | How many characters left start the warning. |

### isRingHidden

Whether a count is far enough over its limit to show the number alone.

#### Signature

```ts
isRingHidden(left: number): boolean
```

Returns: `true` from ten over on.

#### Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `left` | `number` | Characters left; negative past the limit. |

### CharacterCountSync.Options

Configuration for characterCount.

#### Members

| Member | Type | Description |
| --- | --- | --- |
| `for` | `string` | The `id` of the field counted. |
| `max` | `number` |  |
| `warn` | `number` | How many characters left show the number. |
| `holdSubmit` | `boolean` | Disables the field's form's submit buttons while it is empty or over the limit. |
| `labels` | `{ remaining: string; over: string }` | Announcements, with `{count}` replaced by the characters left or over. |

### CharacterCountState

Where a field stands against its limit, which the count's `data-state` carries.

#### Signature

```ts
type CharacterCountState = "empty" | "ok" | "warn" | "over"
```

One of `"empty"`, `"ok"`, `"warn"`, `"over"`.
