# String

> A text value. The most common property type, and the fallback shape several others render as.

Source: CBX documentation, version 4.0 preview (unreleased). Canonical page: https://docs.configbox.at/docs/4.0-preview/technical/property-types/string. Last updated 2026-07-27.

---
A text value. The most common property type, and the fallback shape several others render as.

**Storage kind:** `column` · **Column:** `varchar(255)`

Reach for it for any free text: names, codes, URLs, labels that are not customer-facing. Reach for
something else when the text is not really free —
[`translatable`](https://docs.configbox.at/docs/4.0-preview/technical/property-types/translatable) if the shop shows it to customers in their language,
[`number`](https://docs.configbox.at/docs/4.0-preview/technical/property-types/number) if it is a quantity or a price,
[`dropdown`](https://docs.configbox.at/docs/4.0-preview/technical/property-types/dropdown) if there is a fixed set of valid values,
[`json`](https://docs.configbox.at/docs/4.0-preview/technical/property-types/json) if the column holds a JSON document (a `string` HTML-escapes on the way in and
would corrupt it).

## Settings

| Setting | Meaning |
|---|---|
| `maxLength` | `maxlength` attribute on the input. Was `size`; a shim still routes the old key |
| `stringType` | See below. `'stringOrNumber'` accepts either a number or text |
| `unique` | The column carries a UNIQUE index — validated here, see below |
| `copySuffix` | `true` for `"Name (1)"`, or `function($value, $attempt)`. Permits copying a `unique` value |
| `unit` | A suffix shown next to the input, e.g. `px`, `days` |
| `style` | Inline CSS on the input — used sparingly, for narrow numeric-looking fields |
| `editorWidth` / `editorHeight` | WYSIWYG size, defaults `100%` / `400px`. Only with `USE_HTMLEDITOR` |
| `options` | `USE_TEXTAREA`, `USE_HTMLEDITOR`, `ALLOW_RAW`, `ALLOW_HTML` |

## One type, three widgets

The `options` flags decide what the form renders, and nothing else changes:

| Flag | Widget | Use for |
|---|---|---|
| *(none)* | `<input type="text">` | Single-line values. `maxLength` applies here |
| `USE_TEXTAREA` | `<textarea>` | Multi-line plain text. Give the column a wider `dataType` |
| `USE_HTMLEDITOR` | The platform's WYSIWYG | Rich text. Pair with `ALLOW_HTML` or the markup is stripped on the way in |

`maxLength` only produces a `maxlength` attribute on the plain input — it is a form hint, not a
storage limit. The column width comes from `dataType`, and a `USE_TEXTAREA` field on the default
`varchar(255)` will silently truncate.

## `stringType`

Governs how the value is normalised on the way in and formatted on the way out:

| Value | Behaviour |
|---|---|
| *(unset)* / `'string'` | Plain text, untouched |
| `'stringOrNumber'` | If the input parses as a number, the localised decimal mark is normalised to a dot; otherwise it is left as text |
| `'number'` | Localised decimal mark normalised to a dot; empty stored as `0`; localised again on output |
| `'price'` | As `'number'`, plus `cbprice()` formatting on output |
| `'time'` | Localised decimal mark on output only |

Only `stringOrNumber` appears in any shipped definition. The others are still implemented, but
`stringType => 'number'` and `'price'` are how numeric fields *used* to be declared — those have all
been converted to the [`number`](https://docs.configbox.at/docs/4.0-preview/technical/property-types/number) type, which gives you range validation, decimals,
currency symbols and the right column type. **Do not declare a new one.** `stringOrNumber` is the
case that genuinely remains: a field that holds either, such as a value that may be a literal or a
formula.

## `unique` and `copySuffix`

`unique => true` says the column carries a UNIQUE index, and turns two raw database errors into
things the operator can act on:

- **On save**, `check()` queries whether the value is still free (excluding this record) and refuses
  with *"Another record already uses the …"* on the field, instead of letting MySQL answer
  `Duplicate entry 'EUR' for key 'code'` — an index name where a field name should be.
- **On copy**, the value has to be made distinct, which is what `copySuffix` is for:

```php
'unique' => true, 'copySuffix' => true                                        // "Autumn Sale" → "Autumn Sale (1)"
'unique' => true, 'copySuffix' => function($value, $attempt) { … }            // your own scheme
```

Copying a record whose `unique` property has **no** `copySuffix` is **refused with a reason**, not
attempted. That is often correct — a currency code is ISO 4217, and `EUR (1)` is not a currency.

Suffixing tries up to 100 candidates before giving up: if a hundred variants are all taken, something
is wrong with the data and hammering the database further will not fix it. An empty value is never
suffixed — a UNIQUE index is not usually guarding emptiness, and `required` is the key that governs
that.

When a suffix is applied and the result would exceed `maxLength`, the **original** is shortened, not
the suffix. The suffix is the part doing the work.

@see number.md — for anything numeric
@see translatable.md — for anything a customer reads
@see ../com_configbox_property_definition_settings.md §4
