Refactor de calculadoras com Design System

Suite de calculadoras médicas refatorada como Web Components nativos, 100% aderentes ao design system, com a11y AA+ e zero dependências JS.

Cliente
Plataforma de educação médica B2C, #1 no Brasil
Setor
EdTech médica
Categoria
Papel
Front-end developer
Duração
2025
Stack
HTMLCSSJavaScript vanillaWeb ComponentsDesign Tokens
S01

Contexto

O que é: refactor completo de uma suite de calculadoras médicas (IMC, TFG, dose pediátrica) para Web Components nativos, aderentes ao design system corporativo e com WCAG AA+. Zero framework, zero build step. Live em sanarmed.com/ferramentas-medicas.

Contexto: suite herdada com código inconsistente, sem acessibilidade e fora do design system. Cada calculadora era uma ilha de HTML/CSS inline, impossível de atualizar sem tocar N arquivos.

S02

Problema

Impossível atualizar visual sem tocar N arquivos. Zero acessibilidade. Não aderente ao design system (cores, tipografia, spacing).

S03

Abordagem

Refactor completo como Web Components nativos. Um component por calculadora, compartilhando base class e tokens CSS. Zero framework, zero build step, full a11y.

S04

Execução

Cada calculadora é um customElement. Form controls nativos com labels corretas, aria-live para resultado dinâmico, navegação por teclado completa.

javascriptassets/js/calculators/bmi-calculator.js
class BmiCalculator extends HTMLElement {
  connectedCallback() {
    this.render();
    this.form = this.querySelector('form');
    this.output = this.querySelector('[data-output]');
    this.band = this.querySelector('[data-band]');
    this.live = this.querySelector('[data-live]');
    this.form.addEventListener('input', () => this.compute());
  }

  compute() {
    const weight = Number(this.form.weight.value);
    const height = Number(this.form.height.value) / 100;
    if (!weight || !height) return this.announce('');

    const bmi = weight / (height * height);
    const band = this.classify(bmi);
    this.output.textContent = bmi.toFixed(1);
    this.band.textContent = band;
    this.announce(`IMC ${bmi.toFixed(1)}, ${band}`);
  }

  classify(bmi) {
    if (bmi < 18.5) return 'Abaixo do peso';
    if (bmi < 25) return 'Peso saudável';
    if (bmi < 30) return 'Sobrepeso';
    return 'Obesidade';
  }

  announce(message) {
    this.live.textContent = message;
  }
}

customElements.define('bmi-calculator', BmiCalculator);
Web Component nativo, zero framework.
cssassets/css/components/calculator.css
.calculator {
  display: grid;
  gap: var(--s-5);
  padding: var(--s-6);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-bg-2);
  font-family: var(--font-body);
}

.calculator__output {
  font-family: var(--font-display);
  font-size: var(--fs-3xl);
  font-weight: 500;
  letter-spacing: var(--tracking-tighter);
  color: var(--color-ink);
}
Componente aderente ao design system via tokens compartilhados.
S05

Resultados

100%
Aderência ao design system
Tokens compartilhados
AA+
WCAG contraste e navegação
Validado com axe
0 KB
Dependências JS externas
Zero framework
S06

Output reutilizável

Base class CalculatorComponent, biblioteca de design tokens, padrão de a11y replicável para qualquer formulário dinâmico do ecossistema.

Cada calculadora é um nó na camada semântica descrita no case 7, linkagem por embeddings: da página da calculadora, o usuário é roteado pro exame correspondente, pro código CID e pro curso da especialidade.