JavaScript: Calculadora do Dígito Verificador GTIN/EAN

Tela da calculadora do dígito verificador GTIN/EAN feita com JavaScript e Bootstrap

Todo código de barras de produto (EAN-13 na embalagem do varejo, UPC-A em itens importados, DUN-14 na caixa de embarque) termina em um dígito verificador. Ele é calculado a partir dos demais números e permite que o leitor de código de barras, o ERP ou o emissor de NF-e confirmem que o código foi lido ou digitado corretamente.

Neste tutorial vamos construir, do zero, uma calculadora do dígito verificador GTIN/EAN em JavaScript, com interface em Bootstrap 5. A ferramenta gera o dígito verificador a partir do código incompleto e também valida um GTIN já completo. No final você encontra o código completo em um único arquivo e o resultado esperado para códigos de teste reais.

Nível: iniciante a intermediário. Você precisa conhecer HTML e ter noções de funções e eventos em JavaScript.

O que vamos construir

Uma página única, responsiva e acessível, com dois modos de uso:

  • Gerar dígito: o usuário informa 7, 11, 12 ou 13 dígitos e a calculadora devolve o dígito verificador, o GTIN completo e o tipo identificado (GTIN-8, GTIN-12, GTIN-13 ou GTIN-14).
  • Validar GTIN: o usuário informa um código completo (8, 12, 13 ou 14 dígitos) e a calculadora informa se o dígito verificador está correto e, se não estiver, qual seria o dígito certo.

Recursos implementados:

  • Algoritmo módulo 10 da GS1, com os pesos 3 e 1 aplicados da direita para a esquerda
  • Limpeza automática de espaços, pontos e hifens colados junto com o código
  • Identificação do tipo de GTIN pelo tamanho
  • Mensagens de erro no próprio campo (padrão de validação do Bootstrap), anunciadas por leitores de tela
  • Botão para copiar o GTIN gerado
  • Lógica isolada em funções puras, fáceis de reaproveitar em outros projetos

Stack: HTML5, Bootstrap 5.3 (via CDN), Bootstrap Icons e JavaScript puro, sem build.

Tempo estimado: 30 a 45 minutos.

Se você só precisa do resultado, a mesma lógica está disponível na calculadora de dígito verificador GTIN do msdicas.

Pré-requisitos

  • Um editor de código, como o VS Code
  • Um navegador atualizado (Chrome, Edge, Firefox ou Safari)
  • Conexão com a internet para carregar o Bootstrap pela CDN

Entendendo o dígito verificador GTIN/EAN

GTIN (Global Trade Item Number) é o número de identificação de itens comerciais mantido pela GS1, organização responsável pelo padrão de códigos de barras. “EAN” é o nome antigo que ainda aparece no dia a dia (EAN-13, EAN-8). Existem quatro tamanhos:

FormatoNome usualDígitos no totalDígitos que você informaUso típico
GTIN-8EAN-887Embalagens pequenas
GTIN-12UPC-A1211Produtos dos EUA e do Canadá
GTIN-13EAN-131312Varejo no Brasil e na maior parte do mundo
GTIN-14DUN-14 / ITF-141413Caixas e unidades logísticas

O último dígito de todos eles é o verificador. Para entender a regra com mais profundidade, o impacto na gestão de estoque e os erros mais comuns em cadastros, leia o guia Cálculo do dígito verificador para códigos de barras GTIN.

O algoritmo módulo 10 da GS1

O método oficial da GS1 funciona assim:

  1. Pegue o código sem o dígito verificador.
  2. Começando pelo dígito mais à direita, multiplique os dígitos alternadamente por 3, 1, 3, 1…
  3. Some todos os resultados.
  4. O dígito verificador é o número que falta para a soma chegar ao próximo múltiplo de 10. Em fórmula: (10 - (soma % 10)) % 10. O % 10 final faz com que uma soma que já é múltipla de 10 resulte em 0, e não em 10.

Atenção à direção dos pesos. O erro mais comum em implementações é atribuir os pesos a partir da esquerda. Isso funciona por coincidência no EAN-13, que tem 12 dígitos de entrada (quantidade par), mas gera o dígito errado no GTIN-8, no GTIN-12 e no GTIN-14. A versão anterior deste tutorial tinha esse problema. O código abaixo já está corrigido.

Exemplo manual com um EAN-13 real

Vamos calcular o verificador de 400638133393, cujo código completo é 4006381333931:

Dígito (da esquerda para a direita)400638133393
Peso (atribuído a partir da direita)131313131313
Produto40018324193999
  • Soma: 4 + 0 + 0 + 18 + 3 + 24 + 1 + 9 + 3 + 9 + 9 + 9 = 89
  • Próximo múltiplo de 10: 90
  • Dígito verificador: 90 − 89 = 1, e o GTIN completo fica 4006381333931

Veja agora o GTIN-8 7351353, com 7 dígitos, em que o primeiro dígito recebe peso 3:

Dígito7351353
Peso3131313
Produto213151959

Soma = 63, então o dígito é 70 − 63 = 7 e o código completo fica 73513537. Com os pesos invertidos, o resultado seria 5, o que produziria um código inválido.

Estrutura de arquivos

Para manter o tutorial simples, tudo fica em um único arquivo. Em um projeto maior, separe o CSS e o JavaScript em arquivos próprios.

calculadora-gtin/
└── index.html   # interface, estilos e script

Passo 1: estrutura HTML com Bootstrap 5

Comece com o esqueleto HTML5 e carregue o CSS do Bootstrap e o Bootstrap Icons no <head>:

<!doctype html>
<html lang="pt-BR">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Calculadora do Dígito Verificador GTIN/EAN</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
    <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet" />
  </head>
  <body class="bg-body-tertiary">
    <main class="container py-5">
      <!-- cartão da calculadora -->
    </main>
  </body>
</html>
  • lang="pt-BR" informa o idioma aos leitores de tela e aos mecanismos de busca.
  • A meta viewport é o que faz o layout responsivo funcionar em celulares.
  • <main> marca o conteúdo principal da página, o que facilita a navegação por tecnologias assistivas.

O cartão e a escolha do modo

Dentro do <main>, um cartão centralizado reúne a calculadora. A escolha entre gerar e validar usa um button group do Bootstrap montado com botões de rádio. Assim o controle continua funcionando com teclado e é anunciado corretamente por leitores de tela:

<div class="row justify-content-center">
  <div class="col-12 col-md-8 col-lg-6">
    <div class="card shadow-sm border-0">
      <div class="card-body p-4">
        <h1 class="h4 mb-1">
          <i class="bi bi-upc-scan" aria-hidden="true"></i>
          Calculadora do dígito verificador GTIN/EAN
        </h1>
        <p class="text-body-secondary small mb-4">GTIN-8, GTIN-12 (UPC-A), GTIN-13 (EAN-13) e GTIN-14 (DUN-14)</p>

        <fieldset class="mb-3">
          <legend class="form-label fs-6">O que você quer fazer?</legend>
          <div class="btn-group w-100" role="group">
            <input type="radio" class="btn-check" name="modo" id="modoGerar" value="gerar" checked />
            <label class="btn btn-outline-primary" for="modoGerar">Gerar dígito</label>
            <input type="radio" class="btn-check" name="modo" id="modoValidar" value="validar" />
            <label class="btn btn-outline-primary" for="modoValidar">Validar GTIN</label>
          </div>
        </fieldset>

        <!-- formulário -->
      </div>
    </div>
  </div>
</div>

O formulário

O campo de entrada usa inputmode="numeric" para abrir o teclado numérico no celular. Usamos type="text", e não type="number", porque o GTIN é um identificador, não um valor numérico: type="number" descartaria zeros à esquerda (comuns no UPC-A) e mostraria setas de incremento sem utilidade aqui.

<form id="formGtin" novalidate>
  <label for="codigo" class="form-label" id="rotuloCodigo">Código sem o dígito verificador</label>
  <div class="input-group has-validation">
    <input
      type="text"
      class="form-control form-control-lg font-monospace"
      id="codigo"
      inputmode="numeric"
      autocomplete="off"
      maxlength="20"
      aria-describedby="ajudaCodigo erroCodigo"
      placeholder="Ex.: 789100010000"
    />
    <button type="submit" class="btn btn-primary" id="btnCalcular">
      <i class="bi bi-calculator-fill" aria-hidden="true"></i>
      <span id="textoBotao">Calcular</span>
    </button>
    <div class="invalid-feedback" id="erroCodigo"></div>
  </div>
  <div class="form-text" id="ajudaCodigo">Informe 7, 11, 12 ou 13 dígitos. Espaços, pontos e hifens são ignorados.</div>
</form>

Alguns detalhes importantes:

  • <form> com botão type="submit": a tecla Enter passa a disparar o cálculo sem nenhum código extra.
  • novalidate: desliga os balões nativos do navegador para que as mensagens de erro sigam o padrão visual do Bootstrap.
  • aria-describedby: associa a dica e a mensagem de erro ao campo, e o leitor de tela lê as duas ao focar o input.
  • maxlength="20": dá margem para quem cola o código com separadores (por exemplo, 789-1000-10000).

A área de resultado

O resultado fica em uma região com aria-live="polite", que faz os leitores de tela anunciarem o conteúdo sempre que ele muda. Ela começa oculta com o atributo hidden:

<div id="resultado" class="mt-4" aria-live="polite" hidden></div>

Por que não usar um modal para os erros? A versão anterior deste tutorial exibia erros em um modal. Na prática, o modal interrompe o fluxo, exige um clique extra para fechar e afasta a mensagem do campo com problema. Mostrar o erro abaixo do input é o padrão recomendado pelo próprio guia de validação do Bootstrap.

Passo 2: estilização

O Bootstrap cobre quase tudo. Só precisamos de alguns ajustes para destacar o GTIN no resultado:

<style>
  .gtin-resultado {
    font-size: clamp(1.5rem, 6vw, 2.25rem);
    letter-spacing: 0.12em;
    word-break: break-all;
  }
  .gtin-resultado .dv {
    color: var(--bs-primary);
    font-weight: 700;
    text-decoration: underline;
  }
</style>
  • clamp() deixa o tamanho da fonte fluido: legível no celular sem ficar exagerado no desktop.
  • letter-spacing separa os dígitos e facilita a conferência visual.
  • A classe .dv destaca o dígito verificador usando a variável de cor do Bootstrap. O sublinhado garante que o destaque não dependa só da cor.

Passo 3: a lógica em JavaScript

Vamos separar o código em duas camadas:

  1. Funções puras (normalizarCodigo, calcularDigitoVerificador, gerarGtin, validarGtin): recebem valores e devolvem valores, sem tocar no DOM. Podem ser copiadas para um back-end Node.js ou para qualquer outro projeto.
  2. Camada de interface: lê o formulário, chama as funções puras e exibe o resultado.

Normalizando a entrada

function normalizarCodigo(valor) {
  return String(valor ?? "").replace(/\D/g, "");
}

A expressão regular /\D/g remove tudo o que não é dígito. Isso permite colar códigos com espaços, pontos ou hifens vindos de planilhas e sistemas. String(valor ?? '') evita erro caso a função receba null ou undefined.

Calculando o dígito verificador

Esta é a função central. Ela percorre o código da direita para a esquerda, alternando os pesos 3 e 1:

function calcularDigitoVerificador(codigoSemDigito) {
  let soma = 0;
  let peso = 3; // o dígito mais à direita sempre recebe peso 3

  for (let i = codigoSemDigito.length - 1; i >= 0; i--) {
    soma += Number(codigoSemDigito[i]) * peso;
    peso = peso === 3 ? 1 : 3;
  }

  return (10 - (soma % 10)) % 10;
}

Por percorrer a partir da direita, a mesma função serve para os quatro formatos. Não é preciso tratar a quantidade de dígitos, par ou ímpar, como caso especial.

Identificando o tipo de GTIN

Um objeto de mapeamento relaciona a quantidade de dígitos informada ao formato:

const TIPOS_POR_TAMANHO_SEM_DV = {
  7: "GTIN-8 (EAN-8)",
  11: "GTIN-12 (UPC-A)",
  12: "GTIN-13 (EAN-13)",
  13: "GTIN-14 (DUN-14)",
};

Gerando um GTIN completo

function gerarGtin(valor) {
  const codigo = normalizarCodigo(valor);
  const tipo = TIPOS_POR_TAMANHO_SEM_DV[codigo.length];

  if (!tipo) {
    throw new Error(`Informe 7, 11, 12 ou 13 dígitos. Você informou ${codigo.length}.`);
  }

  const digito = calcularDigitoVerificador(codigo);
  return { tipo, codigo, digito, gtin: codigo + digito };
}

Em vez de devolver só o dígito, a função devolve um objeto com tudo o que a interface precisa. Entradas inválidas geram uma exceção com mensagem pronta para o usuário.

Validando um GTIN existente

function validarGtin(valor) {
  const gtin = normalizarCodigo(valor);
  const tipo = TIPOS_POR_TAMANHO_SEM_DV[gtin.length - 1];

  if (!tipo) {
    throw new Error(`Um GTIN completo tem 8, 12, 13 ou 14 dígitos. Você informou ${gtin.length}.`);
  }

  const corpo = gtin.slice(0, -1);
  const informado = Number(gtin.slice(-1));
  const esperado = calcularDigitoVerificador(corpo);

  return { tipo, gtin, valido: informado === esperado, informado, esperado };
}

A validação reaproveita o cálculo: separa o último dígito, recalcula o verificador sobre o restante e compara os dois.

Passo 4: interface, eventos e tratamento de erros

Com a lógica pronta, conectamos o formulário. Primeiro, as referências aos elementos:

const form = document.getElementById("formGtin");
const campo = document.getElementById("codigo");
const erro = document.getElementById("erroCodigo");
const resultado = document.getElementById("resultado");

Exibindo e limpando erros

function mostrarErro(mensagem) {
  erro.textContent = mensagem;
  campo.classList.add("is-invalid");
  campo.setAttribute("aria-invalid", "true");
  resultado.hidden = true;
  campo.focus();
}

function limparErro() {
  erro.textContent = "";
  campo.classList.remove("is-invalid");
  campo.removeAttribute("aria-invalid");
}

A classe is-invalid ativa a borda vermelha e exibe o .invalid-feedback do Bootstrap. O atributo aria-invalid informa o mesmo estado às tecnologias assistivas.

Montando o resultado com segurança

function criarElemento(tag, classes, texto) {
  const el = document.createElement(tag);
  if (classes) el.className = classes;
  if (texto !== undefined) el.textContent = texto;
  return el;
}

Todo conteúdo dinâmico entra via textContent, nunca via innerHTML. Aqui a entrada já é sanitizada para conter só dígitos, mas manter esse hábito evita falhas de XSS quando o código for adaptado para outros dados.

O evento de envio

form.addEventListener("submit", (evento) => {
  evento.preventDefault();
  limparErro();

  try {
    if (modoAtual() === "gerar") {
      exibirGeracao(gerarGtin(campo.value));
    } else {
      exibirValidacao(validarGtin(campo.value));
    }
  } catch (e) {
    mostrarErro(e.message);
  }
});
  • preventDefault() impede que o formulário recarregue a página.
  • O try/catch converte as exceções das funções puras em mensagens no campo.
  • As funções exibirGeracao, exibirValidacao e modoAtual estão no código completo a seguir. Elas apenas montam os elementos do resultado e leem o rádio selecionado.

Código completo

Copie o conteúdo abaixo para um arquivo index.html e abra no navegador. Não é preciso servidor nem instalação.

<!doctype html>
<html lang="pt-BR">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Calculadora do Dígito Verificador GTIN/EAN</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
    <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet" />
    <style>
      .gtin-resultado {
        font-size: clamp(1.5rem, 6vw, 2.25rem);
        letter-spacing: 0.12em;
        word-break: break-all;
      }
      .gtin-resultado .dv {
        color: var(--bs-primary);
        font-weight: 700;
        text-decoration: underline;
      }
    </style>
  </head>
  <body class="bg-body-tertiary">
    <main class="container py-5">
      <div class="row justify-content-center">
        <div class="col-12 col-md-8 col-lg-6">
          <div class="card shadow-sm border-0">
            <div class="card-body p-4">
              <h1 class="h4 mb-1">
                <i class="bi bi-upc-scan" aria-hidden="true"></i>
                Calculadora do dígito verificador GTIN/EAN
              </h1>
              <p class="text-body-secondary small mb-4">GTIN-8, GTIN-12 (UPC-A), GTIN-13 (EAN-13) e GTIN-14 (DUN-14)</p>

              <fieldset class="mb-3">
                <legend class="form-label fs-6">O que você quer fazer?</legend>
                <div class="btn-group w-100" role="group">
                  <input type="radio" class="btn-check" name="modo" id="modoGerar" value="gerar" checked />
                  <label class="btn btn-outline-primary" for="modoGerar">Gerar dígito</label>
                  <input type="radio" class="btn-check" name="modo" id="modoValidar" value="validar" />
                  <label class="btn btn-outline-primary" for="modoValidar">Validar GTIN</label>
                </div>
              </fieldset>

              <form id="formGtin" novalidate>
                <label for="codigo" class="form-label" id="rotuloCodigo">Código sem o dígito verificador</label>
                <div class="input-group has-validation">
                  <input
                    type="text"
                    class="form-control form-control-lg font-monospace"
                    id="codigo"
                    inputmode="numeric"
                    autocomplete="off"
                    maxlength="20"
                    aria-describedby="ajudaCodigo erroCodigo"
                    placeholder="Ex.: 789100010000"
                  />
                  <button type="submit" class="btn btn-primary" id="btnCalcular">
                    <i class="bi bi-calculator-fill" aria-hidden="true"></i>
                    <span id="textoBotao">Calcular</span>
                  </button>
                  <div class="invalid-feedback" id="erroCodigo"></div>
                </div>
                <div class="form-text" id="ajudaCodigo">Informe 7, 11, 12 ou 13 dígitos. Espaços, pontos e hifens são ignorados.</div>
              </form>

              <div id="resultado" class="mt-4" aria-live="polite" hidden></div>
            </div>
          </div>
        </div>
      </div>
    </main>

    <script>
      "use strict";

      /* ---------- Lógica pura (sem DOM) ---------- */

      const TIPOS_POR_TAMANHO_SEM_DV = {
        7: "GTIN-8 (EAN-8)",
        11: "GTIN-12 (UPC-A)",
        12: "GTIN-13 (EAN-13)",
        13: "GTIN-14 (DUN-14)",
      };

      function normalizarCodigo(valor) {
        return String(valor ?? "").replace(/\D/g, "");
      }

      function calcularDigitoVerificador(codigoSemDigito) {
        let soma = 0;
        let peso = 3; // o dígito mais à direita sempre recebe peso 3

        for (let i = codigoSemDigito.length - 1; i >= 0; i--) {
          soma += Number(codigoSemDigito[i]) * peso;
          peso = peso === 3 ? 1 : 3;
        }

        return (10 - (soma % 10)) % 10;
      }

      function gerarGtin(valor) {
        const codigo = normalizarCodigo(valor);
        const tipo = TIPOS_POR_TAMANHO_SEM_DV[codigo.length];

        if (!tipo) {
          throw new Error(`Informe 7, 11, 12 ou 13 dígitos. Você informou ${codigo.length}.`);
        }

        const digito = calcularDigitoVerificador(codigo);
        return { tipo, codigo, digito, gtin: codigo + digito };
      }

      function validarGtin(valor) {
        const gtin = normalizarCodigo(valor);
        const tipo = TIPOS_POR_TAMANHO_SEM_DV[gtin.length - 1];

        if (!tipo) {
          throw new Error(`Um GTIN completo tem 8, 12, 13 ou 14 dígitos. Você informou ${gtin.length}.`);
        }

        const corpo = gtin.slice(0, -1);
        const informado = Number(gtin.slice(-1));
        const esperado = calcularDigitoVerificador(corpo);

        return { tipo, gtin, valido: informado === esperado, informado, esperado };
      }

      /* ---------- Interface ---------- */

      const form = document.getElementById("formGtin");
      const campo = document.getElementById("codigo");
      const erro = document.getElementById("erroCodigo");
      const resultado = document.getElementById("resultado");
      const rotulo = document.getElementById("rotuloCodigo");
      const ajuda = document.getElementById("ajudaCodigo");
      const textoBotao = document.getElementById("textoBotao");

      const TEXTOS = {
        gerar: {
          rotulo: "Código sem o dígito verificador",
          ajuda: "Informe 7, 11, 12 ou 13 dígitos. Espaços, pontos e hifens são ignorados.",
          botao: "Calcular",
          placeholder: "Ex.: 789100010000",
        },
        validar: {
          rotulo: "GTIN completo",
          ajuda: "Informe 8, 12, 13 ou 14 dígitos, incluindo o dígito verificador.",
          botao: "Validar",
          placeholder: "Ex.: 7891000100004",
        },
      };

      function modoAtual() {
        return document.querySelector('input[name="modo"]:checked').value;
      }

      function criarElemento(tag, classes, texto) {
        const el = document.createElement(tag);
        if (classes) el.className = classes;
        if (texto !== undefined) el.textContent = texto;
        return el;
      }

      function mostrarErro(mensagem) {
        erro.textContent = mensagem;
        campo.classList.add("is-invalid");
        campo.setAttribute("aria-invalid", "true");
        resultado.hidden = true;
        campo.focus();
      }

      function limparErro() {
        erro.textContent = "";
        campo.classList.remove("is-invalid");
        campo.removeAttribute("aria-invalid");
      }

      function exibirGeracao({ tipo, codigo, digito, gtin }) {
        const alerta = criarElemento("div", "alert alert-success mb-0");
        alerta.append(criarElemento("p", "small text-uppercase fw-semibold mb-1", tipo));

        const numero = criarElemento("p", "gtin-resultado font-monospace mb-2");
        numero.append(codigo, criarElemento("span", "dv", String(digito)));
        alerta.append(numero);

        alerta.append(criarElemento("p", "mb-3", `Dígito verificador: ${digito}`));

        const copiar = criarElemento("button", "btn btn-sm btn-outline-success");
        copiar.type = "button";
        copiar.innerHTML = '<i class="bi bi-clipboard" aria-hidden="true"></i> ';
        copiar.append("Copiar GTIN");
        copiar.addEventListener("click", async () => {
          try {
            await navigator.clipboard.writeText(gtin);
            copiar.lastChild.textContent = "Copiado!";
          } catch {
            copiar.lastChild.textContent = "Não foi possível copiar";
          }
        });
        alerta.append(copiar);

        resultado.replaceChildren(alerta);
        resultado.hidden = false;
      }

      function exibirValidacao({ tipo, gtin, valido, informado, esperado }) {
        const alerta = criarElemento("div", `alert ${valido ? "alert-success" : "alert-danger"} mb-0`);
        alerta.append(criarElemento("p", "small text-uppercase fw-semibold mb-1", tipo));
        alerta.append(criarElemento("p", "gtin-resultado font-monospace mb-2", gtin));

        const mensagem = valido
          ? "GTIN válido: o dígito verificador está correto."
          : `GTIN inválido: o dígito verificador informado é ${informado}, mas o correto é ${esperado}.`;
        alerta.append(criarElemento("p", "mb-0 fw-semibold", mensagem));

        resultado.replaceChildren(alerta);
        resultado.hidden = false;
      }

      document.querySelectorAll('input[name="modo"]').forEach((radio) => {
        radio.addEventListener("change", () => {
          const textos = TEXTOS[modoAtual()];
          rotulo.textContent = textos.rotulo;
          ajuda.textContent = textos.ajuda;
          textoBotao.textContent = textos.botao;
          campo.placeholder = textos.placeholder;
          limparErro();
          resultado.hidden = true;
          campo.focus();
        });
      });

      campo.addEventListener("input", limparErro);

      form.addEventListener("submit", (evento) => {
        evento.preventDefault();
        limparErro();

        try {
          if (modoAtual() === "gerar") {
            exibirGeracao(gerarGtin(campo.value));
          } else {
            exibirValidacao(validarGtin(campo.value));
          }
        } catch (e) {
          mostrarErro(e.message);
        }
      });
    </script>
  </body>
</html>

Resultado do código

Ao abrir o index.html, você verá um cartão centralizado com o seletor Gerar dígito / Validar GTIN, o campo de código e o botão Calcular. Os casos abaixo usam códigos de exemplo reais e mostram exatamente o que a calculadora exibe.

Modo “Gerar dígito”

Você digitaTipo exibidoDígito verificadorGTIN completo exibido
7351353GTIN-8 (EAN-8)773513537
03600029145GTIN-12 (UPC-A)2036000291452
400638133393GTIN-13 (EAN-13)14006381333931
789-1000-10000GTIN-13 (EAN-13)47891000100004
1400638133393GTIN-14 (DUN-14)814006381333938

No caso do EAN-13, a tela mostra:

GTIN-13 (EAN-13)
400638133393[1]        ← o "1" aparece destacado em azul e sublinhado
Dígito verificador: 1
[ Copiar GTIN ]

Modo “Validar GTIN”

Você digitaMensagem exibida
4006381333931GTIN válido: o dígito verificador está correto.
4006381333932GTIN inválido: o dígito verificador informado é 2, mas o correto é 1.
73513535GTIN inválido: o dígito verificador informado é 5, mas o correto é 7.

Mensagens de erro

EntradaModoMensagem abaixo do campo
12345GerarInforme 7, 11, 12 ou 13 dígitos. Você informou 5.
(vazio)GerarInforme 7, 11, 12 ou 13 dígitos. Você informou 0.
123456789ValidarUm GTIN completo tem 8, 12, 13 ou 14 dígitos. Você informou 9.

O campo fica com borda vermelha, recebe o foco de volta e a mensagem some assim que o usuário começa a digitar de novo.

Possíveis melhorias

  • Gerar a imagem do código de barras: bibliotecas como o JsBarcode desenham EAN-13, EAN-8 e UPC em SVG ou canvas a partir do GTIN gerado. Se você quer ver isso pronto, o msdicas tem o Gerador de Etiquetas de Produtos, que usa o JsBarcode para montar uma etiqueta completa: código de barras EAN-8, UPC-A ou EAN-13 com cálculo automático do dígito verificador, nome do produto, layout nos formatos Pimaco e exportação em PDF pronta para imprimir.
  • Validação em lote: aceitar uma lista de códigos (um por linha ou colada do Excel) e exibir uma tabela com os válidos e inválidos, algo útil para saneamento de cadastro de produtos no ERP.
  • Módulo ES reutilizável: mover as funções puras para um gtin.js com export e importá-las em qualquer página ou projeto que precise do cálculo.
  • Checagem de prefixo: alertar quando o GTIN-13 não começar com 789 ou 790, faixas atribuídas à GS1 Brasil. Isso não invalida o código, mas ajuda a identificar produtos importados.

Limite importante: um dígito verificador correto garante apenas que o número é matematicamente consistente. Ele não prova que o GTIN foi licenciado pela GS1 nem que pertence ao produto. Para a NF-e, a SEFAZ valida o GTIN informado nos campos cEAN e cEANTrib contra o Cadastro Centralizado de GTIN. Por isso, gerar um GTIN “inventado” com dígito válido não resolve rejeições fiscais.

Conclusão

Você construiu uma calculadora do dígito verificador GTIN/EAN que gera e valida os quatro formatos do padrão GS1, com interface responsiva em Bootstrap 5, mensagens de erro acessíveis e lógica isolada em funções reutilizáveis. O ponto central do tutorial é o algoritmo módulo 10 com os pesos 3 e 1 aplicados a partir da direita, detalhe que separa uma implementação correta de uma que falha em três dos quatro formatos.

Para ver a ferramenta pronta em produção, acesse a calculadora de dígito verificador GTIN do msdicas. Se quiser se aprofundar nos recursos usados aqui, veja também estilização e validação de formulários com Bootstrap 5 e o guia básico de validação de formulários com JavaScript.

Referências

  1. GS1 — How to calculate a check digit manually: método oficial de cálculo do dígito verificador. gs1.org/services/how-calculate-check-digit-manually
  2. GS1 — Global Trade Item Number (GTIN): definição e formatos do GTIN. gs1.org/standards/id-keys/gtin
  3. GS1 Brasil: associação responsável pelo licenciamento de códigos no Brasil. gs1br.org
  4. Bootstrap 5.3 — Validation: padrão de mensagens is-invalid e invalid-feedback. getbootstrap.com/docs/5.3/forms/validation
  5. Bootstrap Icons: biblioteca de ícones usada na interface. icons.getbootstrap.com
  6. MDN — String.prototype.replace() e expressões regulares. developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/String/replace
  7. MDN — Atributo aria-live: regiões dinâmicas anunciadas por leitores de tela. developer.mozilla.org/pt-BR/docs/Web/Accessibility/ARIA/Attributes/aria-live

Comentários

Seja o primeiro a comentar!

Deixe seu comentário