Skip to main content

Overview

The BotonDescarga component is a styled download link button for PDF files and other downloadable resources. It features:
  • Native HTML download functionality
  • Hover state with color transition
  • Download emoji icon (📥)
  • Flex layout with icon and text
  • Purple gradient styling matching the app theme
  • No external dependencies (pure CSS-in-JS)

Props

archivo
string
required
URL or path to the file to be downloaded. Can be a relative path (e.g., /pdfs/report.pdf) or absolute URL
titulo
string
required
Display text for the download button, describing what will be downloaded

Usage Example

From ProyectoDetalle.jsx, showing how download buttons are rendered from project data:
import BotonDescarga from "../components/BotonDescarga";
import TarjetasContenido from "../components/TarjetasContenido";

export default function DetalleProyecto() {
  const proyectoData = proyectos.find((p) => p.id === slug);

  return (
    <div>
      {proyectoData.pdfs && proyectoData.pdfs.length > 0 && (
        <TarjetasContenido
          titulo="📄 Descargas"
          contenido={
            <div style={{
              display: "flex",
              flexDirection: "column",
              paddingTop: "10px",
              gap: "10px",
            }}>
              {proyectoData.pdfs.map((pdf, i) => (
                <BotonDescarga
                  key={i}
                  archivo={pdf.archivo}
                  titulo={pdf.titulo}
                />
              ))}
            </div>
          }
        />
      )}
    </div>
  );
}

Expected Data Structure

The proyectoData.pdfs array should have this structure:
const proyectoData = {
  pdfs: [
    {
      archivo: "/pdfs/informe-final.pdf",
      titulo: "Informe Final del Proyecto"
    },
    {
      archivo: "/pdfs/presentacion.pdf",
      titulo: "Presentación PPT"
    },
    {
      archivo: "/pdfs/metodologia.pdf",
      titulo: "Metodología de Investigación"
    }
  ]
};

Component Structure

The component is implemented as a styled anchor tag with inline event handlers:
function BotonDescarga({ archivo, titulo }) {
  return (
    <a
      href={archivo}
      download
      style={{
        textDecoration: "none",
        backgroundColor: "#836FFF",
        color: "#F0F3FF",
        padding: "12px",
        borderRadius: "8px",
        display: "flex",
        alignItems: "center",
        gap: "10px",
        fontWeight: "bold",
        transition: "0.3s",
        cursor: "pointer",
      }}
      onMouseOver={(e) => (e.currentTarget.style.backgroundColor = "#6f5acb")}
      onMouseOut={(e) => (e.currentTarget.style.backgroundColor = "#836FFF")}
    >
      <span style={{ fontSize: "1.2rem" }}>📥</span>
      <div style={{ fontSize: "0.9rem" }}>{titulo}</div>
    </a>
  );
}

Styling Details

Default State

PropertyValue
Background Color#836FFF (purple)
Text Color#F0F3FF (off-white)
Padding12px (all sides)
Border Radius8px
Font Weightbold
LayoutFlex with 10px gap

Hover State

PropertyValue
Background Color#6f5acb (darker purple)
Transition0.3s (smooth color change)
Cursorpointer

Icon and Text

  • Icon: 📥 emoji at 1.2rem font size
  • Text: 0.9rem font size, inherits bold weight
  • Gap: 10px spacing between icon and text

Download Behavior

The download attribute on the <a> tag triggers a file download instead of navigation:
<a href={archivo} download>
This works for same-origin files. For cross-origin files, the browser may navigate instead of downloading.

Specifying Download Filename

You can suggest a filename for the download:
<a
  href={archivo}
  download="custom-filename.pdf"
>

Accessibility Considerations

Improve accessibility by adding ARIA labels and file size information:
<a
  href={archivo}
  download
  aria-label={`Descargar ${titulo} (PDF)`}
  style={{...}}
>
  <span style={{ fontSize: "1.2rem" }}>📥</span>
  <div style={{ fontSize: "0.9rem" }}>
    {titulo}
    <span style={{ fontSize: "0.8rem", opacity: 0.8 }}> (2.3 MB)</span>
  </div>
</a>

Multiple Buttons Layout

When rendering multiple download buttons, use a flex column layout with gap:
<div style={{
  display: "flex",
  flexDirection: "column",
  gap: "10px",
}}>
  <BotonDescarga
    archivo="/pdfs/report1.pdf"
    titulo="Informe Parte 1"
  />
  <BotonDescarga
    archivo="/pdfs/report2.pdf"
    titulo="Informe Parte 2"
  />
  <BotonDescarga
    archivo="/pdfs/appendix.pdf"
    titulo="Anexos"
  />
</div>

Customization Examples

Different File Types

Change the emoji icon based on file type:
// Word document
<span style={{ fontSize: "1.2rem" }}>📄</span>

// Excel spreadsheet  
<span style={{ fontSize: "1.2rem" }}>📊</span>

// Image
<span style={{ fontSize: "1.2rem" }}>🖼️</span>

// ZIP archive
<span style={{ fontSize: "1.2rem" }}>📦</span>

Icon from Material-UI

Replace the emoji with a Material-UI icon:
import DownloadIcon from "@mui/icons-material/Download";

<a href={archivo} download style={{...}}>
  <DownloadIcon sx={{ fontSize: "1.2rem" }} />
  <div style={{ fontSize: "0.9rem" }}>{titulo}</div>
</a>

Gradient Background

Add a gradient instead of solid color:
style={{
  background: "linear-gradient(135deg, #836FFF, #6f5acb)",
  // ... other styles
}}

Event Handling Enhancement

Track download events with analytics:
function BotonDescarga({ archivo, titulo }) {
  const handleDownload = () => {
    // Track download event
    console.log(`Downloaded: ${titulo}`);
    // Or send to analytics
    // analytics.track('file_download', { file: titulo });
  };

  return (
    <a
      href={archivo}
      download
      onClick={handleDownload}
      style={{...}}
    >
      {/* ... */}
    </a>
  );
}

Browser Compatibility

The download attribute is supported in all modern browsers:
  • Chrome 14+
  • Firefox 20+
  • Safari 10.1+
  • Edge 13+
For cross-origin downloads, proper CORS headers must be set on the server.

Security Considerations

  • Always validate that the archivo URL points to a safe, expected location
  • For user-uploaded files, implement server-side file type validation
  • Consider adding virus scanning for uploaded PDFs
  • Use Content-Security-Policy headers to restrict download sources

Build docs developers (and LLMs) love