Como criar módulos personalizados no HubSpot - Guia completo para 2026

A Equipe Rapid

Se você trabalha com o HubSpot CMS, os módulos personalizados são a habilidade mais importante que você pode aprender. Eles dão aos editores de conteúdo controle total sobre o conteúdo da página, mantendo o código limpo, rápido e fácil de manter.

Mas aqui está o problema — a maioria dos desenvolvedores HubSpot constrói módulos da maneira errada. Eles escrevem CSS inchado, ignoram o agrupamento de campos, inserem tags de cabeçalho diretamente no código (hardcode) e ignoram completamente a performance. O resultado? Páginas lentas, editores frustrados e um código bagunçado que ninguém quer manter.

Este guia cobre tudo o que você precisa para construir módulos personalizados prontos para produção no HubSpot — do jeito certo. Com exemplos de código reais, estrutura de campos adequada, melhores práticas de HubL e dicas de performance que realmente importam.

Entendendo os Módulos Personalizados do HubSpot

Um módulo personalizado é um bloco de conteúdo reutilizável composto por quatro arquivos dentro do Gerenciador de Design (Design Manager):

  • module.html — Seu template HTML com tags HubL que renderizam conteúdo dinâmico
  • fields.json — Define quais campos os editores de conteúdo veem e com os quais interagem
  • module.css — Estilos opcionais com escopo limitado a este módulo
  • meta.json — Configurações como rótulo, ícone e quais tipos de templates podem usar este módulo

Pense nisso como construir um bloco de Lego. Você o projeta uma vez com todos os pontos de conexão corretos e, em seguida, os editores de conteúdo podem usá-lo em qualquer lugar — em qualquer página, em qualquer seção — sem nunca tocar no código.

Configurando o meta.json da Maneira Correta

Antes de construir qualquer coisa, configure seu módulo adequadamente. Aqui está um meta.json limpo para um módulo de Seção Hero:

{% module_block module "widget_efc8ab62-075c-4dc5-90bb-70cd64137afa" %}{% module_attribute "child_css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "code_block" is_json="true" %}"{
  \"label\": \"Seção Hero\",
  \"css_assets\": [],
  \"external_js\": [],
  \"global\": false,
  \"help_text\": \"Uma seção hero flexível com título, descrição, imagem e botões de chamada para ação (CTA).\",
  \"host_template_types\": [\"PAGE\", \"BLOG_LISTING\", \"BLOG_POST\"],
  \"icon\": \"\",
  \"is_available_for_new_content\": true,
  \"js_assets\": [],
  \"other_assets\": [],
  \"smart_type\": \"NOT_SMART\",
  \"categories\": [\"DESIGN\"]
}"{% end_module_attribute %}{% module_attribute "css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "label" is_json="true" %}null{% end_module_attribute %}{% module_attribute "module_id" is_json="true" %}321957934793{% end_module_attribute %}{% module_attribute "schema_version" is_json="true" %}2{% end_module_attribute %}{% module_attribute "tag" is_json="true" %}"module"{% end_module_attribute %}{% end_module_block %}

Duas coisas a notar aqui. Primeiro, host_template_types controla onde este módulo pode ser usado. Defina como PAGE para módulos exclusivos de páginas, ou inclua BLOG_POST se ele também deve funcionar em templates de blog. Nunca deixe aberto para templates de e-mail se o seu módulo usa CSS ou JS — e-mails não têm suporte para eles. Segundo, adicione sempre um help_text (texto de ajuda) significativo. Isso aparece no Gerenciador de Design e ajuda sua equipe a entender o que o módulo faz sem precisar ler o código.

Construindo uma Estrutura Adequada para o fields.json

O arquivo fields.json é onde a maioria dos desenvolvedores erra. Uma lista plana com mais de 15 campos torna a experiência de edição dolorosa. Agrupar campos relacionados cria uma interface limpa e intuitiva.

Configurações da Seção — Todo Módulo Precisa Disso

Antes de qualquer campo de conteúdo, todo módulo deve ter um grupo de Configurações da Seção. Isso dá aos editores de conteúdo controle sobre o ID da seção, classes personalizadas e visibilidade:

{% module_block module "widget_2cb5c016-551b-4589-9d8b-2c61c7e5bd7d" %}{% module_attribute "child_css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "code_block" is_json="true" %}"{
  \"id\": \"section_settings\",
  \"name\": \"section_settings\",
  \"label\": \"Configurações da Seção\",
  \"type\": \"group\",
  \"children\": [
    {
      \"id\": \"section_id\",
      \"name\": \"section_id\",
      \"label\": \"ID da Seção\",
      \"type\": \"text\",
      \"help_text\": \"Adicione um ID único para links âncora. Exemplo: secao-hero\",
      \"default\": \"\"
    },
    {
      \"id\": \"section_class\",
      \"name\": \"section_class\",
      \"label\": \"Classe CSS Personalizada\",
      \"type\": \"text\",
      \"help_text\": \"Adicione classes Tailwind ou CSS personalizadas ao contêiner da seção.\",
      \"default\": \"\"
    },
    {
      \"id\": \"section_visible\",
      \"name\": \"section_visible\",
      \"label\": \"Exibir Seção\",
      \"type\": \"boolean\",
      \"help_text\": \"Desative para ocultar esta seção sem excluir seu conteúdo.\",
      \"default\": true
    }
  ]
}"{% end_module_attribute %}{% module_attribute "css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "label" is_json="true" %}null{% end_module_attribute %}{% module_attribute "module_id" is_json="true" %}321957934793{% end_module_attribute %}{% module_attribute "schema_version" is_json="true" %}2{% end_module_attribute %}{% module_attribute "tag" is_json="true" %}"module"{% end_module_attribute %}{% end_module_block %}

Por que isso é importante? Os editores de conteúdo frequentemente precisam ocultar uma seção temporariamente, adicionar um link âncora para navegação ou aplicar uma classe personalizada para uma estilização especial. Sem esses campos, eles precisam pedir a um desenvolvedor para cada pequena mudança. Com eles, eles são autossuficientes.

Grupo de Conteúdo — Títulos com Controle de SEO

Nunca insira a tag de cabeçalho diretamente no código (hardcode). Sempre forneça um campo de escolha para que os editores possam controlar a hierarquia de SEO:

{% module_block module "widget_f8321e21-939f-4518-9379-2b1c3ef5cbe8" %}{% module_attribute "child_css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "code_block" is_json="true" %}"{
  \"id\": \"content\",
  \"name\": \"content\",
  \"label\": \"Conteúdo\",
  \"type\": \"group\",
  \"children\": [
    {
      \"id\": \"heading\",
      \"name\": \"heading\",
      \"label\": \"Título\",
      \"type\": \"text\",
      \"help_text\": \"Título principal. Mantenha abaixo de 60 caracteres para obter os melhores resultados de SEO.\",
      \"default\": \"Construa Algo Incrível\"
    },
    {
      \"id\": \"heading_tag\",
      \"name\": \"heading_tag\",
      \"label\": \"Tag do Título\",
      \"type\": \"choice\",
      \"help_text\": \"Use H1 apenas uma vez por página. Use H2 para todos os outros títulos de seção.\",
      \"choices\": [
        [\"h1\", \"H1 — Título Principal da Página\"],
        [\"h2\", \"H2 — Título da Seção\"],
        [\"h3\", \"H3 — Título da Subseção\"]
      ],
      \"default\": \"h2\"
    },
    {
      \"id\": \"description\",
      \"name\": \"description\",
      \"label\": \"Descrição\",
      \"type\": \"textarea\",
      \"help_text\": \"Texto de apoio abaixo do título. Recomenda-se 1-2 frases.\",
      \"default\": \"\"
    }
  ]
}"{% end_module_attribute %}{% module_attribute "css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "label" is_json="true" %}null{% end_module_attribute %}{% module_attribute "module_id" is_json="true" %}321957934793{% end_module_attribute %}{% module_attribute "schema_version" is_json="true" %}2{% end_module_attribute %}{% module_attribute "tag" is_json="true" %}"module"{% end_module_attribute %}{% end_module_block %}

Note que a tag de título padrão está definida como h2, e não h1. Isso é intencional. A maioria das páginas deve ter apenas um H1, e isso geralmente é tratado pelo primeiro módulo. Todo módulo subsequente deve ter o padrão H2. Se o editor colocar este módulo como a primeira seção de uma página, ele mesmo pode mudar para H1.

Grupo de Botões — Use Campos de Link, Não CTAs

Um erro comum é usar o módulo CTA do HubSpot para cada botão. CTAs são poderosos, mas adicionam sobrecarga de rastreamento e deixam o carregamento da página mais lento quando usados em excesso. Para a maioria dos botões, um simples campo de link com um campo de texto é tudo o que você precisa:

{% module_block module "widget_c832fe56-56b7-47c6-a8f0-4db7d136ca79" %}{% module_attribute "child_css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "code_block" is_json="true" %}"{
  \"id\": \"primary_button\",
  \"name\": \"primary_button\",
  \"label\": \"Botão Principal\",
  \"type\": \"group\",
  \"children\": [
    {
      \"id\": \"button_text\",
      \"name\": \"button_text\",
      \"label\": \"Texto do Botão\",
      \"type\": \"text\",
      \"default\": \"Começar\"
    },
    {
      \"id\": \"button_link\",
      \"name\": \"button_link\",
      \"label\": \"Link do Botão\",
      \"type\": \"link\",
      \"default\": {
        \"url\": { \"href\": \"#\", \"type\": \"EXTERNAL\" },
        \"open_in_new_tab\": false,
        \"no_follow\": false
      }
    }
  ]
}"{% end_module_attribute %}{% module_attribute "css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "label" is_json="true" %}null{% end_module_attribute %}{% module_attribute "module_id" is_json="true" %}321957934793{% end_module_attribute %}{% module_attribute "schema_version" is_json="true" %}2{% end_module_attribute %}{% module_attribute "tag" is_json="true" %}"module"{% end_module_attribute %}{% end_module_block %}

O tipo de campo de link oferece automaticamente aos editores opções para URL, nova aba e nofollow — tudo sem nenhum trabalho extra de sua parte.

Convenções de Nomenclatura de Campos

Como você nomeia os campos importa mais do que você imagina. Os editores de conteúdo veem esses rótulos toda vez que editam uma página. Seja específico:

  • ❌ "Imagem" — qual imagem? Fundo? Perfil? Hero?
  • ✅ "Imagem de Fundo do Hero" — instantaneamente claro
  • ❌ "Alternância" (Toggle) — alternar o quê?
  • ✅ "Exibir Seção" ou "Ativar Sobreposição de Fundo" — descreve exatamente o que isso controla
  • ❌ "Texto" — todo campo é texto
  • ✅ "Texto do Botão" ou "Subtítulo" — específico e óbvio

Adicione também help_text (texto de ajuda) a cada campo. Uma descrição de 10 palavras agora economiza uma conversa de 10 minutos no Slack mais tarde.

Escrevendo o HTML do Módulo + HubL

Agora vamos construir o module.html em si. É aqui que todos os campos se juntam em um componente renderizado.

O module.html Completo da Seção Hero

{% module_block module "widget_a3a43b89-297c-4796-91ca-eba1b2531c6f" %}{% module_attribute "child_css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "code_block" is_json="true" %}"{%- if module.section_settings.section_visible -%}
<section
  {%- if module.section_settings.section_id %} id=\"{{ module.section_settings.section_id }}\"{% endif -%}
  class=\"relative overflow-hidden {{ module.section_settings.section_class }}\"
>
  <div class=\"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16 sm:py-20 lg:py-24\">
    <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-12 items-center\">

      <div class=\"flex flex-col gap-6\">

        {%- if module.content.heading -%}
        <{{ module.content.heading_tag }} class=\"text-4xl sm:text-5xl lg:text-6xl font-bold tracking-tight text-slate-900\">
          {{- module.content.heading -}}
        </{{ module.content.heading_tag }}>
        {%- endif -%}

        {%- if module.content.description -%}
        <p class=\"text-lg text-slate-600 leading-relaxed max-w-xl\">
          {{- module.content.description -}}
        </p>
        {%- endif -%}

        {%- if module.primary_button.button_text -%}
        <div class=\"flex flex-wrap gap-4 mt-2\">
          <a
            href=\"{{ module.primary_button.button_link.url.href }}\"
            {%- if module.primary_button.button_link.open_in_new_tab %} target=\"_blank\" rel=\"noopener noreferrer\"{% endif -%}
            class=\"inline-flex items-center px-8 py-4 text-base font-semibold text-white bg-blue-600 rounded-xl hover:bg-blue-700 transition-colors\"
          >
            {{- module.primary_button.button_text -}}
          </a>
        </div>
        {%- endif -%}

      </div>

      {%- if module.hero_image.image.src -%}
      <div class=\"relative\">
        <img
          src=\"{{ module.hero_image.image.src }}\"
          alt=\"{{ module.hero_image.image.alt }}\"
          width=\"{{ module.hero_image.image.width }}\"
          height=\"{{ module.hero_image.image.height }}\"
          loading=\"lazy\"
          class=\"w-full h-auto rounded-2xl\"
        >
      </div>
      {%- endif -%}

    </div>
  </div>
</section>
{%- endif -%}"{% end_module_attribute %}{% module_attribute "css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "label" is_json="true" %}null{% end_module_attribute %}{% module_attribute "module_id" is_json="true" %}321957934793{% end_module_attribute %}{% module_attribute "schema_version" is_json="true" %}2{% end_module_attribute %}{% module_attribute "tag" is_json="true" %}"module"{% end_module_attribute %}{% end_module_block %}

Vamos analisar os padrões críticos usados neste código.

Controle de Espaço em Branco com {%- -%}

Cada tag HubL no código acima usa a sintaxe de traço: {%- -%} em vez de {% %}. Essa única mudança faz uma diferença enorme no seu HTML renderizado.

Sem os traços, o HubL insere linhas em branco onde quer que ele processe uma tag. O código-fonte da sua página acaba cheio de espaços em branco desnecessários — linhas vazias entre cada elemento. Isso torna o HTML mais pesado, mais difícil de depurar e um pouco mais lento para ser analisado.

Com traços, o HubL remove esse espaço em branco de forma limpa. O HTML renderizado é enxuto, mínimo e exatamente o que o navegador precisa. Em uma página com mais de 20 módulos, isso pode reduzir o tamanho do seu arquivo HTML de forma perceptível.

O mesmo se aplica à saída de variáveis: use {{- -}} em vez de {{ }} para evitar espaços em branco ao redor de valores dinâmicos.

Tags de Título Dinâmicas

O título usa o valor do campo diretamente como a tag HTML:

{% module_block module "widget_3613ce56-de83-4e88-a170-a5800aed74d1" %}{% module_attribute "child_css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "code_block" is_json="true" %}"<{{ module.content.heading_tag }}>
  {{- module.content.heading -}}
</{{ module.content.heading_tag }}>"{% end_module_attribute %}{% module_attribute "css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "label" is_json="true" %}null{% end_module_attribute %}{% module_attribute "module_id" is_json="true" %}321957934793{% end_module_attribute %}{% module_attribute "schema_version" is_json="true" %}2{% end_module_attribute %}{% module_attribute "tag" is_json="true" %}"module"{% end_module_attribute %}{% end_module_block %}

Se o editor selecionar "H2" na lista suspensa, isso será renderizado como uma tag <h2> adequada. Se ele selecionar "H1", será renderizado como <h1>. O editor tem controle total do SEO sem precisar de um desenvolvedor.

Renderização Condicional

Cada seção de conteúdo é envolvida em uma verificação if. Se o campo de título estiver vazio, nenhuma tag <h2> será renderizada. Se o texto do botão estiver vazio, nenhum botão aparecerá. Se a imagem não tiver origem (source), a coluna da imagem desaparecerá completamente.

Isso impede que elementos HTML vazios apareçam na página — sem layouts quebrados, sem divs vazias ocupando espaço, sem problemas de acessibilidade devido a tags de título vazias.

Melhores Práticas de Imagem no HubSpot

Ao usar o tipo de campo de imagem do HubSpot, sempre exiba os valores do campo diretamente — src, alt, width e height. O campo de imagem do HubSpot já é otimizado para SEO. Ele fornece atributos de imagem responsivos e um tratamento adequado do texto alternativo (alt) nativamente.

Não substitua esses valores por atributos inseridos diretamente no código (hardcoded). Apenas adicione loading="lazy" para imagens abaixo da dobra (below-the-fold) para melhorar a performance da página.

Usando Macros para Configurações de Seção Reutilizáveis

Se todo módulo precisa de configurações de seção (ID, classe, visibilidade), você não deveria copiar esse código em todo module.html. Em vez disso, crie um arquivo de macro uma vez e importe-o em todos os lugares.

Crie macros/section-macros.html no seu tema

{% module_block module "widget_cbbb1b5a-738a-4ace-a95d-b1c5b6554fa2" %}{% module_attribute "child_css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "code_block" is_json="true" %}"{%- macro section_attrs(settings) -%}
  {%- if settings.section_id %} id=\"{{ settings.section_id }}\"{% endif -%}
  {%- if settings.section_class %} class=\"{{ settings.section_class }}\"{% endif -%}
{%- endmacro -%}"{% end_module_attribute %}{% module_attribute "css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "label" is_json="true" %}null{% end_module_attribute %}{% module_attribute "module_id" is_json="true" %}321957934793{% end_module_attribute %}{% module_attribute "schema_version" is_json="true" %}2{% end_module_attribute %}{% module_attribute "tag" is_json="true" %}"module"{% end_module_attribute %}{% end_module_block %}

Importe e use em qualquer módulo

{% module_block module "widget_cfe27dbe-3a3e-4505-bbb8-75211709451d" %}{% module_attribute "child_css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "code_block" is_json="true" %}"{%- import '../macros/section-macros.html' as section_macros -%}

{%- if module.section_settings.section_visible -%}
<section {{ section_macros.section_attrs(module.section_settings) }}>
  {# Conteúdo do módulo aqui #}
</section>
{%- endif -%}"{% end_module_attribute %}{% module_attribute "css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "label" is_json="true" %}null{% end_module_attribute %}{% module_attribute "module_id" is_json="true" %}321957934793{% end_module_attribute %}{% module_attribute "schema_version" is_json="true" %}2{% end_module_attribute %}{% module_attribute "tag" is_json="true" %}"module"{% end_module_attribute %}{% end_module_block %}

Escreva uma vez. Importe em 50 módulos. Quando você precisar mudar como os IDs das seções funcionam, atualize um arquivo e todo módulo receberá a atualização. É assim que os temas profissionais do HubSpot são construídos.

Estratégia CSS — Pare de Escrever CSS no Módulo

Esta pode ser a seção mais importante de todo este guia. A maioria dos desenvolvedores HubSpot escreve CSS dentro do arquivo module.css de cada módulo. Isso cria uma bagunça — estilos duplicados entre módulos, espaçamento inconsistente, tamanhos de arquivos crescentes e páginas que carregam mais devagar a cada novo módulo.

Em Vez Disso, Use as Classes Utilitárias do Tailwind CSS

Olhe para o module.html acima. Não há nenhum CSS personalizado. Cada estilo é aplicado através das classes utilitárias do Tailwind diretamente no HTML:

  • max-w-7xl mx-auto px-4 — contêiner com largura máxima, centralizado, preenchimento horizontal
  • grid grid-cols-1 lg:grid-cols-2 gap-12 — grade responsiva de duas colunas
  • text-4xl sm:text-5xl lg:text-6xl font-bold — tamanho de título responsivo
  • hover:bg-blue-700 transition-colors — efeito hover com transição suave

Benefícios dessa abordagem:

  • Um arquivo CSS para todo o tema — e não 50 arquivos module.css separados
  • Minificado e purgado — apenas as classes que você realmente usa são incluídas
  • Sistema de design consistente — cada módulo usa a mesma escala de espaçamento, paleta de cores e pontos de interrupção (breakpoints)
  • Melhor contraste de cores — a paleta padrão do Tailwind é projetada com os padrões de acessibilidade WCAG AA em mente
  • Qualquer desenvolvedor pode ler — sem necessidade de caçar pelas folhas de estilo para entender o que uma classe faz

Quando Você Realmente Precisa do module.css

A única vez que se deve escrever no module.css é para coisas que o Tailwind genuinamente não consegue lidar — tipicamente animações personalizadas ou padrões complexos de pseudo-elementos:

{% module_block module "widget_5180834c-63c9-4260-a456-822e6a475bd0" %}{% module_attribute "child_css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "code_block" is_json="true" %}"@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: translateY(0); }
}

.hero-animate {
  animation: fadeInUp 0.6s ease-out;
}"{% end_module_attribute %}{% module_attribute "css" is_json="true" %}null{% end_module_attribute %}{% module_attribute "label" is_json="true" %}null{% end_module_attribute %}{% module_attribute "module_id" is_json="true" %}321957934793{% end_module_attribute %}{% module_attribute "schema_version" is_json="true" %}2{% end_module_attribute %}{% module_attribute "tag" is_json="true" %}"module"{% end_module_attribute %}{% end_module_block %}

Todo o resto deve estar no CSS global do seu tema ou ser tratado pelos utilitários do Tailwind. Ponto final.

JavaScript — Apenas Quando Necessário

A mesma regra se aplica ao module.js. A maioria dos módulos não precisa de JavaScript.

Módulos que não precisam de JS: seções hero, blocos de texto e imagem, grades de recursos, cartões de depoimentos, tabelas de preços, seções de rodapé. Estes são puramente visuais — o HTML e o CSS cuidam de tudo.

Módulos que precisam de JS: acordeões, carrosséis/sliders, componentes de abas, pop-ups modais, validação de formulários, animações acionadas por rolagem (scroll).

Quando você escrever JavaScript, mantenha-o 'vanilla' (puro). Nada de jQuery em 2026. O HubSpot carrega o module.js apenas uma vez por tipo de módulo, mesmo que o módulo apareça várias vezes em uma página — mas isso ainda adiciona peso à sua página. Seja intencional sobre cada script que você incluir.

Contraste de Cores e Acessibilidade

O Google considera os sinais de acessibilidade nos rankings de pesquisa. Construir módulos acessíveis não é apenas uma boa prática — impacta diretamente o seu SEO.

Se você está usando o Tailwind CSS, já tem uma vantagem. A paleta de cores padrão do Tailwind foi projetada com proporções de contraste adequadas. Atenha-se a essas combinações seguras:

  • text-slate-900 sobre bg-white — taxa de contraste 15.4:1 (passa no AAA)
  • text-white sobre bg-slate-900 — taxa de contraste 15.4:1 (passa no AAA)
  • text-slate-700 sobre bg-slate-50 — taxa de contraste 8.1:1 (passa no AAA)

Evite texto claro em fundos claros. Uma taxa de contraste abaixo de 4.5:1 falha no WCAG AA e pode prejudicar seus rankings de pesquisa.

Checklist de Acessibilidade do Módulo

  • Toda imagem tem um atributo alt significativo proveniente do campo de imagem do HubSpot
  • A hierarquia de títulos é lógica — H1 seguido por H2, nunca pulando para H4
  • Os links têm um texto descritivo — "Leia o guia completo" e não "Clique aqui"
  • Elementos interativos usam as tags HTML corretas — <a> para links, <button> para ações
  • A cor por si só nunca transmite significado — sempre combine a cor com texto ou ícones

Testando Seus Módulos

Antes de publicar qualquer módulo, revise esta checklist:

  • Pré-visualize o módulo na visualização do Gerenciador de Design do HubSpot
  • Teste em uma página real com conteúdo real — não apenas com texto falso (dummy text)
  • Verifique todos os quatro pontos de interrupção (breakpoints): celular (320px), tablet (768px), laptop (1024px), desktop (1440px)
  • Verifique se existe apenas um H1 na página quando este módulo está presente
  • Teste com campos vazios — o layout ainda parece limpo?
  • Teste com conteúdo muito longo — o título quebra a linha (wrap) adequadamente?
  • Execute uma auditoria no Lighthouse para obter as pontuações de Performance, Acessibilidade e SEO
  • Veja o código-fonte da página — há linhas em branco desnecessárias ou elementos vazios?

Erros Comuns Que Prejudicam Seus Módulos

Escrever CSS em cada módulo. Isso cria estilos duplicados e carregamentos de página mais pesados. Use as classes utilitárias do Tailwind ou escreva o CSS global na folha de estilos do seu tema. O CSS do módulo deve ser seu último recurso.

Adicionar JavaScript desnecessariamente. Módulos de conteúdo estático como seções hero, grades de recursos e depoimentos não precisam de JavaScript. Cada script adiciona peso à página.

Inserir tags de título diretamente no código (hardcoding). Se você escrever <h2> diretamente no seu HTML, os editores de conteúdo não poderão controlar a hierarquia de SEO. Sempre use um campo de escolha e renderize a tag dinamicamente.

Ignorar o espaço em branco do HubL. Usar {% %} em vez de {%- -%} enche seu HTML renderizado de linhas em branco. A sintaxe com traço remove os espaços em branco e produz um resultado mais limpo e leve.

Listas de campos planas sem grupos. Vinte campos não agrupados no editor de páginas é um pesadelo para os editores de conteúdo. Agrupe campos relacionados — Conteúdo, Imagem, Botão, Configurações da Seção — para que a interface fique limpa e navegável.

Ignorar as configurações da seção. Sem um campo de ID, os editores não podem criar links âncora. Sem um botão de alternância de visibilidade, eles não podem ocultar uma seção temporariamente. Sem um campo de classe personalizada, eles precisam de um desenvolvedor para cada ajuste de estilo. Adicione esses três campos a cada módulo como prática padrão.

Substituir o snippet de imagem do HubSpot. O tipo de campo de imagem do HubSpot já gera um HTML otimizado para SEO com os atributos src, alt, width, height e responsividade adequados. Não substitua isso por código personalizado — basta exibir os valores dos campos diretamente e adicionar loading="lazy" quando apropriado.

Usar CTAs para todos os botões. Os CTAs do HubSpot têm uma sobrecarga de rastreamento. Para botões simples que vinculam a uma página, use uma tag de âncora com um campo de texto e um campo de link em vez disso. Reserve os CTAs para botões que genuinamente precisam de rastreamento e análise.

Conclusão

Construir módulos personalizados no HubSpot não se trata apenas de fazer com que as coisas pareçam certas — trata-se de construir componentes que sejam rápidos, acessíveis, otimizados para SEO e fáceis de usar para os editores de conteúdo.

As técnicas cobertas neste guia — campos agrupados, tags de título dinâmicas, controle de espaços em branco do HubL, classes utilitárias do Tailwind, macros reutilizáveis e o tratamento adequado de imagens — são o que separa o desenvolvimento profissional no HubSpot de um trabalho amador.

Comece a aplicar essas práticas no seu próximo módulo. Seus editores de conteúdo agradecerão, suas páginas carregarão mais rápido e suas pontuações de SEO irão melhorar.


Construir módulos HubSpot do zero leva tempo. O Rapid permite que você faça upload de qualquer captura de tela de interface (UI) e gera um módulo HubSpot completo e pronto para produção — com fields.json, vinculações HubL e a estrutura correta — em menos de 60 segundos. Experimente grátis →

Share this article

Ainda criando módulos manualmente?

Transforme capturas de tela em módulos do HubSpot prontos para uso com IA.