Etiqueta HTML <script>
La etiqueta HTML <script> incrusta o enlaza JavaScript en una página. Aprende src, async vs defer, type="module", ubicación y atributos con ejemplos.
La etiqueta HTML <script> declara scripts del lado del cliente — casi siempre JavaScript — en un documento HTML. Los scripts añaden interactividad: validación de formularios, actualizaciones dinámicas de contenido, manipulación de imágenes y respuesta a eventos del usuario. La etiqueta puede contener el script en línea (entre las etiquetas de apertura y cierre) o cargar un archivo externo mediante el atributo src. Para una visión general más amplia sobre cómo agregar scripts a una página, consulta HTML scripts.
Si conectas un archivo externo con scripts, no incrustes código en la misma etiqueta <script>.
La etiqueta HTML <script> puede colocarse en el elemento <head>, así como dentro del elemento <body>. Los scripts que deben ejecutarse primero se colocan habitualmente en el elemento <head> con defer, o al final del elemento <body>. La etiqueta <script> puede usarse muchas veces en un documento HTML.

Sintaxis
La etiqueta <script> siempre viene en pares — una apertura <script> y un cierre </script>. El código en línea va entre ellas; para un archivo externo, deja la etiqueta vacía y apunta src al archivo:
<script>
// inline JavaScript here
console.log("Hello from inline script");
</script>
<script src="app.js"></script>Ejemplo de script en línea
Para seleccionar un elemento HTML, JavaScript usa comúnmente el método document.getElementById():
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<p id="example"></p>
<script>
document.getElementById("example").innerHTML = "My first JavaScript code";
</script>
</body>
</html>Cargar un script externo
En proyectos reales casi siempre se mantiene el JavaScript en un archivo .js separado y se carga con src. Esto mantiene el HTML limpio, permite que el navegador almacene el script en caché y posibilita reutilizar el mismo archivo en varias páginas:
<script src="app.js" defer></script>Algunos aspectos a tener en cuenta:
- No mezcles ambas formas. Cuando
srcestá presente, cualquier código escrito entre las etiquetas es ignorado. Usa código en línea o unsrc, pero no ambos en la misma etiqueta. type="text/javascript"es innecesario. JavaScript es el lenguaje de scripting predeterminado en el HTML moderno, por lo que puedes omitirtypecompletamente. Solo establecetypecuando realmente necesitestype="module"(ver más abajo).charsetno tiene efecto en scripts externos hoy en día. La codificación de caracteres se obtiene del encabezado HTTPContent-Typedel archivo (y de la propia codificación de la página), así que el atributocharseten<script>está obsoleto — no confíes en él.
async vs. defer
Por defecto, cuando el navegador encuentra un <script src="..."> mientras analiza el HTML, detiene el análisis, descarga el script, lo ejecuta y solo entonces continúa. Esto bloquea el renderizado. Los atributos boolean async y defer solucionan esto — ambos descargan el script en paralelo sin bloquear el análisis — pero difieren en cuándo se ejecuta el script:
| Atributo | ¿Bloquea el análisis? | Cuándo se ejecuta | Orden |
|---|---|---|---|
| (ninguno) | Sí | Inmediatamente al encontrarlo | En orden del documento |
defer | No | Después de que el HTML se haya analizado completamente, justo antes de DOMContentLoaded | En orden del documento |
async | No | En cuanto termina de descargarse | El que termine primero (sin orden garantizado) |
<!-- Runs after the page is parsed, in order. Safe for code that touches the DOM. -->
<script src="app.js" defer></script>
<!-- Runs as soon as it loads, order not guaranteed. Good for independent scripts
like analytics that don't depend on other scripts or the parsed DOM. -->
<script src="analytics.js" async></script>Usa defer cuando los scripts dependen del DOM o entre sí (el caso más común). Usa async para scripts independientes y sin orden específico, como píxeles de seguimiento.
async y defer son atributos boolean — su mera presencia los activa. Escríbelos sin valor (defer), no en el antiguo estilo XHTML defer="defer". Lo mismo aplica a otros atributos boolean como disabled y checked. Ambos atributos son ignorados en scripts en línea (aquellos sin src).
Ubicación del script: <head> vs. final de <body>
Dónde coloques <script> importa porque un script normal bloquea el análisis:
<head>condefer— la recomendación moderna. La descarga comienza de forma temprana mientras el HTML se sigue analizando, y la ejecución espera hasta que el DOM está listo. Obtienes una carga rápida sin bloqueos.- Final de
<body>— el enfoque clásico. Cuando el analizador llega al script, el DOM completo ya existe, por lo que el script puede consultar elementos de forma segura. No se necesita ningún atributo.
<head>
<script src="app.js" defer></script>
</head>
<body>
<!-- page content -->
</body>Evita un <script src> normal (sin async/defer) en <head>, ya que bloquea el renderizado de la página hasta que el script se descarga y ejecuta.
Módulos ES con type="module"
Establecer type="module" convierte el script en un módulo ES. Los scripts de módulo se comportan de forma diferente a los scripts clásicos:
- Soportan
import/export, por lo que puedes dividir el código en varios archivos. - Son diferidos por defecto — los scripts de módulo siempre esperan hasta que el HTML está analizado (no se necesita
defer). - Siempre se ejecutan en modo estricto, y tienen su propio ámbito de nivel superior (las variables no se filtran al objeto global).
<script type="module" src="main.js"></script>
<script type="module">
import { greet } from "./greet.js";
greet("World");
</script>Para compatibilidad con navegadores muy antiguos que no entienden los módulos, puedes combinar un módulo con un script de reserva nomodule — los navegadores modernos ejecutan el módulo e ignoran el de reserva, los más antiguos hacen lo contrario.
Una nota sobre XHTML y el marcado heredado
En el HTML moderno no necesitas un atributo type, y no envuelves el contenido de scripts en línea en una sección CDATA. Ese envoltorio //<![CDATA[ ... //]]> solo era relevante en XHTML, donde el contenido del script se analizaba como marcado y los caracteres especiales como < y & debían escaparse o protegerse. Si estás escribiendo HTML estándar, puedes ignorarlo.
Atributos
| Atributo | Valor | Descripción |
|---|---|---|
src | URL | URL de un archivo de script externo (relativa o absoluta). |
async | (boolean) | El script externo se obtiene en paralelo y se ejecuta en cuanto está disponible, sin bloquear el análisis. |
defer | (boolean) | El script externo se obtiene en paralelo y se ejecuta, en orden, después de que el HTML esté analizado. |
type | tipo de medio | Generalmente omitido (JavaScript es el predeterminado). Establécelo como module para cargar un módulo ES. |
charset | charset | Obsoleto — no tiene efecto; la codificación proviene del Content-Type HTTP del archivo. |
crossorigin | anonymous | use-credentials | Configura CORS para la solicitud del script externo. |
integrity | hash | Hash de Subresource Integrity usado para verificar el script descargado. |
La etiqueta <script> admite los Atributos globales y los Atributos de eventos.