The Pokemon detail page provides in-depth information about each Pokemon with a beautiful, type-themed interface.
Overview
The detail view includes:
Dynamic type-based color theming
Tabbed interface (About, Stats, Moves)
Visual stat bars
High-quality Pokemon artwork
Ability links
Add to favorites functionality
Type-Based Theming
Each Pokemon’s primary type determines the color scheme:
const typeColors = {
normal: '#A8A77A' ,
fire: '#EE8130' ,
water: '#6390F0' ,
electric: '#F7D02C' ,
grass: '#7AC74C' ,
ice: '#96D9D6' ,
fighting: '#C22E28' ,
poison: '#A33EA1' ,
ground: '#E2BF65' ,
flying: '#A98FF3' ,
psychic: '#F95587' ,
bug: '#A6B91A' ,
rock: '#B6A136' ,
ghost: '#735797' ,
dragon: '#6F35FC' ,
dark: '#705746' ,
steel: '#B7B7CE' ,
fairy: '#D685AD' ,
};
const primaryColor = computed (() => {
if ( ! datos . value ?. types ) return '#777' ;
return typeColors [ datos . value . types [ 0 ]. type . name ] || '#777' ;
});
The primary color is applied using CSS custom properties:
< div class = "pokemon-detail" : style = " { '--primary-color' : primaryColor } " >
The header displays Pokemon name, image, types, and number:
< div class = "pokemon-header" >
<div class="pokemon-info">
<h1 class="pokemon-name">
{{ datos.name.charAt(0).toUpperCase() + datos.name.slice(1) }}
</h1>
<div class="pokemon-types">
<span
v-for="type in datos.types"
:key="type.slot"
class="type-badge"
:style="{ backgroundColor: typeColors[type.type.name] || '#777' }"
>
{{ type.type.name }}
</span>
</ div >
< div class = "pokemon-number" >
#{{ ('000' + datos.id).slice(-3) }}
</ div >
< / div >
<div class="pokemon-image-container">
<img
:src="datos.sprites.other['official-artwork'].front_default || datos.sprites.front_default"
:alt="datos.name"
class="pokemon-main-image"
/>
</ div >
< / div >
The header uses a gradient background based on the Pokemon’s primary type for a cohesive visual theme.
Tabbed Interface
The detail view uses a custom tab system:
const activeTab = ref ( 'about' );
< div class = "tabs" >
<button
:class="['tab-button', { active: activeTab === 'about' }]"
@click="activeTab = 'about'"
>
Acerca de
</button>
<button
:class="['tab-button', { active: activeTab === 'stats' }]"
@click="activeTab = 'stats'"
>
Estadísticas
</button>
<button
:class="['tab-button', { active: activeTab === 'moves' }]"
@click="activeTab = 'moves'"
>
Movimientos
</button>
</ div >
About Tab
Displays basic Pokemon information:
< div v-if = " activeTab === 'about' " class = "about-tab" >
<div class="info-row">
<span class="info-label">Altura:</span>
<span class="info-value">{{ (datos.height / 10).toFixed(1) }} m</span>
</ div >
< div class = "info-row" >
<span class="info-label">Peso:</span>
<span class="info-value">{{ (datos.weight / 10).toFixed(1) }} kg</span>
</ div >
< div class = "info-row" >
<span class="info-label">Habilidades:</span>
<div class="abilities">
<RouterLink
v-for="ability in datos.abilities"
:key="ability.ability.name"
:to="`/pokemons/ability/${ability.ability.name}`"
class="ability-link"
>
{{ ability.ability.name.replace('-', ' ') }}
</RouterLink>
</ div >
< / div >
</ div >
Ability names are clickable links that navigate to the Ability Explorer to show all Pokemon with that ability.
Stats Tab
Visualizes Pokemon base stats with animated bars:
const stats = computed (() => {
if ( ! datos . value ?. stats ) return [];
return [
{ name: 'HP' , value: datos . value . stats [ 0 ]. base_stat },
{ name: 'Attack' , value: datos . value . stats [ 1 ]. base_stat },
{ name: 'Defense' , value: datos . value . stats [ 2 ]. base_stat },
{ name: 'Sp. Atk' , value: datos . value . stats [ 3 ]. base_stat },
{ name: 'Sp. Def' , value: datos . value . stats [ 4 ]. base_stat },
{ name: 'Speed' , value: datos . value . stats [ 5 ]. base_stat },
];
});
< div v-else-if = " activeTab === 'stats' " class = "stats-tab" >
<div v-for="stat in stats" :key="stat.name" class="stat-row">
<span class="stat-name">{{ stat.name }}</span>
<div class="stat-bar-container">
<div
class="stat-bar"
:style="{
width: `${Math.min(100, (stat.value / 255) * 100)}%`,
backgroundColor: primaryColor
}"
> </ div >
< / div >
<span class="stat-value">{{ stat.value }}</span>
</ div >
< / div >
Moves Tab
Displays a grid of Pokemon moves:
< div v-else-if = " activeTab === 'moves' " class = "moves-tab" >
<div class="moves-grid">
<span
v-for="(move, index) in datos.moves.slice(0, 20)"
:key="index"
class="move-tag"
>
{{ move.move.name.replace('-', ' ') }}
</span>
</ div >
< / div >
Only the first 20 moves are displayed to keep the interface clean and performant.
Tab Styling
Data Loading
The component fetches Pokemon data using the route parameter:
import { useRoute } from 'vue-router' ;
import { useGetData } from '@/composables/useGetData' ;
const route = useRoute ();
const { getData , datos , error , cargando } = useGetData ();
getData ( `https://pokeapi.co/api/v2/pokemon/ ${ route . params . nombre } ` );
Loading and Error States
< div v-if = " cargando " class = "loading" >
<div class="spinner"> </ div >
< p > Cargando información del Pokémon... </ p >
< / div >
<div v-else-if="error" class="error">
<p>No se pudo cargar la información del Pokémon.</p>
<RouterLink to="/pokemons" class="back-link">Volver a la Pokédex</RouterLink>
</ div >
Responsive Design
The detail view adapts to mobile screens:
@media ( max-width : 768 px ) {
.pokemon-name {
font-size : 2 rem ;
}
.pokemon-content {
padding : 20 px 15 px ;
}
.tab-button {
padding : 8 px 12 px ;
font-size : 0.9 rem ;
}
.info-row {
flex-direction : column ;
gap : 5 px ;
}
.moves-grid {
grid-template-columns : repeat ( auto-fill , minmax ( 100 px , 1 fr ));
}
}
Favorites Add Pokemon to your favorites collection
Ability Explorer View all Pokemon with a specific ability