How to position input field characters inside background boxes

So in my game, I allow the player to enter a 10-character long code. I want to position each character inside a background box using the input field.
195178-screenshot-1.jpg
How can I keep each character in its position while at the same time allowing the player to edit and change the entered code?

I wrote a code for you try to see if it is right for you, if you like it and you want to optimize it I can continue to help you.
It is necessary: that you add this code to your panel and that all the boxes are InputFields, in charactersID and LV set the value corresponding to your fields

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class AddLevel : MonoBehaviour
{
    [SerializeField] private InputField[] charactersID;                     //This array contains all "InputField-Text" GameObject in Hierarchy    (Canvas->UI)
    [SerializeField] string[] stringsID;                                    //This one contains the input values we insert in each inputfield that we will add up 

    [SerializeField] private InputField[] charactersLV;                     
    [SerializeField] string[] stringsLV;                                 

    [Space(20)] [SerializeField] public string ID;                         
    [Space(20)] [SerializeField] public string LEVEL;                      

    private int indexID = 0;                                                //This is a reference for the arrays
    private int indexLV = 0;
    private string tempID;                                                  //This is a temporary variable that will contains ours adds of strings. It will be the integer ID
    private string tempLV;
    private bool runOnce;                                                   //This variable is used for run a method once time and not update every frame

    
    

    private void Awake()
    {
        stringsID = new string[charactersID.Length];                        //Initializing of the strings for each value
        stringsLV = new string[charactersLV.Length];
        runOnce = false;                                                    
    }

    private void Update()
    {
        //Update function can be removed if you want to load script from other event
        Application();
    }


    #region StartProgram
    public void Application()
    {

        //START THE FIRST PART WHERE WE INSERT THE ID VALUE
        //Check if ID area isn't already used or completed
        if (indexID < charactersID.Length)
        {
            if(indexID == 0)
            {
                //Start with first box selected (if-index==0)
                charactersID[indexID].Select();
            }

            //Updated methods
            InsertValueID();
            ReadyToWriteID();
        }

        //Level ready check
        else
        {
            if (indexLV == 0)
            {
                charactersLV[indexLV].Select();               
            }
            InsertValueLevel();
            ReadyToWriteLevel();
        }


    }

    #endregion

    #region ID
    private void InsertValueID()
    {

        runOnce = true;
        if (indexID < charactersID.Length)
            charactersID[indexID].onValueChanged.AddListener(delegate { NextValueID(); });  //onValueChanged can be found in InputField (addListener used for runtime next method)

    
    }

    private void NextValueID() //Selects the next input field once you leave one
    {

        if (runOnce)
        {
            //Here inserted the value we are going to add it to the array String
            ReplaceAtID(stringsID, indexID);

            //check if there are still fields and add index++
            if (indexID < stringsID.Length)
                indexID++;            

            //select the next inputfield
            if (indexID < charactersID.Length)
            {
                charactersID[indexID].Select();
            }
        }

        runOnce = false;
    }

    private void ReplaceAtID(string[] strings, int index)
    {
        //We insert the input value with the position in the string point
        strings[index] = charactersID[index].text;  
        
    }

    private void ReadyToWriteID()
    {
        
        if (indexID == charactersID.Length - 1)
        {
            //At the end we can call the method to write the id
            charactersID[indexID].onValueChanged.AddListener(delegate { GetID(); });
            
        }
    }

    private string GetID()
    {
        for (int i = 0; i < stringsID.Length; i++)
        {

            //sum of each index in array
            tempID += stringsID*;*

Debug.Log(“Writing ID” + tempID);

if (i <= stringsID.Length)
{
ID = tempID;
Debug.Log(“GET ID” + ID);
}
}

tempID = “”;
return ID;

}

#endregion

//SAME SPEECH
#region LEVEL

private void InsertValueLevel()
{

runOnce = true;
if (indexLV < charactersLV.Length)
charactersLV[indexLV].onValueChanged.AddListener(delegate { NextValueLevel(); });

}

private void NextValueLevel()
{

if (runOnce)
{
ReplaceAtLevel(stringsLV, indexLV);

if (indexLV < stringsLV.Length)
indexLV++;

if (indexLV < charactersLV.Length)
{
charactersLV[indexLV].Select();
}
}

runOnce = false;
}

private void ReplaceAtLevel(string[] stringsLV, int indexLV)
{

stringsLV[indexLV] = charactersLV[indexLV].text;

}

private void ReadyToWriteLevel()
{
if (indexLV == charactersLV.Length - 1)
{

charactersLV[indexLV].onValueChanged.AddListener(delegate { GetLevel(); });

}
}

private string GetLevel()
{
for (int i = 0; i < stringsLV.Length; i++)
{

tempLV += stringsLV*;*
Debug.Log("Writing Level: " + tempLV);

if (i <= stringsLV.Length)
{
LEVEL = tempLV;
Debug.Log("Get Level: " + LEVEL);
}
}

tempLV = “”;
return LEVEL;

}

#endregion
}