# Builder max min character Limit for localized fields

**URL:** <https://forum.builder.io/t/builder-max-min-character-limit-for-localized-fields/15918>\
**Category:** General\
**Tags:** react, nextjs, locale\
**Created:** [November 5, 2025, 1:27pm UTC](https://forum.builder.io/t/builder-max-min-character-limit-for-localized-fields/15918 "2025-11-05T13:27:08Z")\
**Posts on this page:** 1\
**Showing post:** 2

<div class="post-metadata">

**Author:** ![manish-sharma](https://avatars.discourse-cdn.com/v4/letter/m/8797f3/32.png) [@manish-sharma](https://forum.builder.io/u/manish-sharma)\
**Post date:** [November 7, 2025, 1:58pm UTC](https://forum.builder.io/t/builder-max-min-character-limit-for-localized-fields/15918/2 "2025-11-07T13:58:16Z")

</div>

Hello @dipanjanbhattacharya ,

The issue was that the locale wasn’t directly accessible through the standard `options` or `context` in the Builder registry. However, the following implementation successfully retrieves the current locale from the Builder state context and applies both minimum and maximum character limits per locale.

Here’s the tested code snippet that works well:

```auto
Builder.registerComponent(Heading, {
  name: "Heading",
  inputs: [
    {
      name: "text",
      type: "string",
      defaultValue: "Add a headline",
      localized: true,
      helperText: "Supports per-locale copy with a 10-120 character range.",
      onChange: (options) => {
        const currentLocale =
          (options.builder &&
            options.builder.state &&
            options.builder.state.context &&
            options.builder.state.context.locale) ||
          options.locale;
        const value = options.get("text") as
          | string
          | Record<string, unknown>
          | undefined
          | null;
        const minLength = 4;
        const maxLength = 12;
        const globalScope =
          typeof globalThis === "object" && globalThis !== null
            ? (globalThis as typeof globalThis & {
                alert?: (value: string) => void;
              })
            : undefined;
        const showAlert = (message: string) => {
          if (typeof globalScope?.alert === "function") {
            globalScope.alert(message);
            return;
          }

          if (typeof alert === "function") {
            alert(message);
          }
        };

        if (typeof value === "string") {
          if (value.length > maxLength) {
            options.set("text", value.slice(0, maxLength));
            showAlert(`Maximum length of ${maxLength} reached${currentLocale ? ` for locale ${currentLocale}` : ""}.`);
          }

          if (value.length !== 0 && value.length < minLength) {
            showAlert(
              `${currentLocale ? `Locale ${currentLocale}` : "Heading text"} must have at least ${minLength} characters.`,
            );
          }
          return;
        }

        if (!value || typeof value !== "object") {
          return;
        }

        const mapCandidate = value as unknown as Map<string, unknown>;
        const isMapLike =
          typeof mapCandidate?.forEach === "function" &&
          typeof mapCandidate?.entries === "function";

        const entries = isMapLike
          ? Array.from(mapCandidate.entries())
          : Object.entries(value as Record<string, unknown>);

        let didModify = false;

        entries.forEach(([locale, localeValue]) => {
          if (locale.startsWith("@") || typeof localeValue !== "string") {
            return;
          }

          if (localeValue.length > maxLength) {
            const truncated = localeValue.slice(0, maxLength);
            if (isMapLike) {
              mapCandidate.set(locale, truncated);
            } else {
              (value as Record<string, unknown>)[locale] = truncated;
            }
            didModify = true;
            showAlert(`Maximum length of ${maxLength} reached for locale ${locale}.`);
          }

          if (localeValue.length !== 0 && localeValue.length < minLength) {
            showAlert(`Locale ${locale} must have at least ${minLength} characters.`);
          }
        });

        if (!isMapLike && didModify) {
          options.set("text", { ...(value as Record<string, unknown>) });
        }
      },
    },
    {
      name: "level",
      type: "string",
      enum: ["h1", "h2", "h3", "h4", "h5", "h6"],
      defaultValue: "h2",
    },
    {
      name: "align",
      type: "string",
      enum: ["left", "center", "right"],
      defaultValue: "left",
    },
  ],
});

```

> **[Input types](https://www.builder.io/c/docs/input-types#onChange)**
>
> Learn about the input types for custom components and data models. This document includes required inputs, optional inputs, and examples

> [@How to get the value of a text box inside a container to update the container style based on the value of the text box?](https://forum.builder.io/t/how-to-get-the-value-of-a-text-box-inside-a-container-to-update-the-container-style-based-on-the-value-of-the-text-box/4839):
>
> Builder content link Builder public api key ce289f18ea2a4567bfcc5038d6ea2892 I have a container “Footer” that i’m trying to change the background color of based on the value of the text box that is inside this container. I’m having some difficulty understanding how to do this in builder using the element data binding. I’ve added a screenshot of the visual editor to show the layer container “Footer” that contains the text box which will either show a text of Register, Filled, Ended, or Cancel…

Thanks,

---

_[View the full topic](https://forum.builder.io/t/builder-max-min-character-limit-for-localized-fields/15918)._
