---
name: sms-editor
category: inputs
summary: "Textarea with live SMS encoding + segment counting"
subpath: "@42/core/sms-editor"
---

Enhances a plain-text `<textarea>` and reports the things that affect SMS cost:
encoding (GSM-7 vs UCS-2), weighted character count and billable segment count.
No formatting toolbar (SMS is plain text). Optional emoji picker via the same
`renderPicker` plugin as `textarea-emoji` (emoji force UCS-2). No styling applied.

```html
<div data-c42-sms-editor>
  <textarea data-c42-sms-input placeholder="Write an SMS…"></textarea>
  <div class="c42-sms-editor-status">
    <span data-c42-sms-counter></span>
    <span data-c42-sms-segments></span>
    <span data-c42-sms-encoding></span>
    <!-- emoji affordance bottom-right (picker drops below) -->
    <span class="c42-sms-editor-emoji">
      <button data-c42-sms-trigger aria-label="Emoji">🙂</button>
      <div data-c42-sms-picker hidden></div>
    </span>
  </div>
  <!-- optional live preview (filled with the escaped message text) -->
  <div data-c42-sms-preview></div>
</div>
```

```ts
import { SmsEditor } from '@42/core/sms-editor';
const sms = new SmsEditor(root, { maxSegments: 1 });
sms.on('smseditor:change', (e) => {
  const { encoding, length, segments, overLimit } = e.detail;
});
```

Segmentation (3GPP TS 23.038): GSM-7 = 160 chars single / 153 per part;
UCS-2 = 70 / 67. GSM-7 extension chars (`^ { } \ [ ] ~ | €`) count as two.
The root reflects `data-encoding="GSM-7|UCS-2"`; when `maxSegments` is exceeded
it gets `data-over-limit`. By default there is no `maxlength` (multi-segment is
allowed); set `maxLength` to enforce a hard cap.

Options: `value`, `maxLength`, `maxSegments`, `emojis`, `renderPicker`
Methods: `insertText(text)`, `getText()`, `getSegmentInfo()`, `focus()`, `value` get/set
Events: `smseditor:change` → `{ text, encoding, length, segments, remaining, overLimit }`
Pure helpers (no DOM): `segment(text)`, `detectEncoding(text)`, `countChars(text, encoding)`

Optional preview: add a `[data-c42-sms-preview]` element and the controller
fills it with the live, escaped message text (toggling `data-empty` when blank).
Device preview (`@42/styles`): wrap that element in `.c42-sms-editor-device` to
render it on an iPhone header background (image ships with `@42/styles`). Purely
opt-in — omit the wrapper for a plain bubble, or omit the element entirely to
keep the editor counters-only. Tune with `--c42-sms-device-pad-top`,
`--c42-sms-device-pad-x`.

```html
<div class="c42-sms-editor-device">
  <div data-c42-sms-preview class="c42-sms-editor-preview"></div>
</div>
```
