Widget Card en Flutter: propiedades, ejemplos y variantes de Material 3

- Andrés Cruz - EN In english

Widget Card en Flutter: propiedades, ejemplos y variantes de Material 3

El widget Card en Flutter es un componente visual de Material Design que se utiliza para mostrar información agrupada dentro de una tarjeta: un contenedor con bordes redondeados, fondo uniforme y una sombra sutil que lo separa del fondo. Puede albergar cualquier tipo de widget —imágenes, texto, botones, formularios— y es uno de los elementos más comunes en aplicaciones móviles y web modernas gracias a la claridad visual que aporta.

Si vienes del desarrollo nativo en Android, como me ocurrió a mí, reconocerás enseguida su parentesco con el clásico CardView: misma filosofía, misma esencia. El Card llegó a Flutter como parte del ecosistema de Material Design y desde entonces se ha convertido en uno de esos widgets que empiezas a usar "porque toca"… y terminas poniendo en todas tus pantallas.

En esta guía te explico qué es el widget Card, cómo funciona, cuáles son sus propiedades principales y cómo sacarle partido con ejemplos reales. Incluyo también algunos trucos que aprendí a fuerza de prueba y error —como ese momento en el que descubrí que un Card solo acepta un child y tuve que replantear por completo mi diseño .

Anteriormente vimos cómo usar los widgets de tipo botón: Floating Action Button, FlatButton, MaterialButton e IconButton. Ahora le toca el turno a este widget.

Qué es un Card en Flutter y para qué sirve

Un Card es un contenedor de Material Design diseñado para mostrar información agrupada dentro de una tarjeta con características visuales bien definidas:

  • Bordes ligeramente redondeados
  • Sombra o elevación configurable
  • Fondo uniforme (blanco por defecto, personalizable)
  • Área táctil clara y delimitada

Su principal ventaja es que te permite construir interfaces limpias y jerarquizadas, evitando pantallas donde todo parece apelmazado. Un Card bien utilizado guía la mirada del usuario hacia el contenido que importa.

Relación con Material Design

El diseño del Card en Flutter sigue fielmente las guías oficiales de Material Design:

  • La elevación indica jerarquía e importancia dentro de la interfaz.
  • La sombra lo separa visualmente del fondo, aportando profundidad.
  • Las esquinas redondeadas suavizan el look general de la UI.
  • Las nuevas variantes de Material 3elevated, filled y outlined— amplían las posibilidades sin necesidad de código adicional.

Elevación, sombra y bordes redondeados

La propiedad elevation es la que genera la sombra y da la sensación de profundidad. En mis pruebas, elevar demasiado un Card —por encima de 10 o 12— hace que parezca flotando artificialmente sobre el fondo. Normalmente trabajo con valores entre 4 y 8, salvo que quiera destacar un componente específico. También puedes personalizar el color de la sombra con la propiedad shadowColor.

Los bordes redondeados se controlan con la propiedad shape, usando RoundedRectangleBorder:

shape: RoundedRectangleBorder(
  borderRadius: BorderRadius.circular(20),
)

Cuanto mayor es el valor de BorderRadius.circular(), más pronunciado es el redondeo. Un valor de 20.0 ya da un aspecto bastante redondeado al Card.

Propiedades principales del widget Card en Flutter

El widget Card expone varias propiedades que conviene conocer para adaptarlo a cualquier diseño. Aquí te las explico agrupadas por funcionalidad:

Color, elevación y sombra

  • color: define el color de fondo del Card. Por defecto usa el color de superficie del tema activo.
  • elevation: controla cuánta sombra proyecta, lo que determina su "altura" visual sobre el fondo.
  • shadowColor: personaliza el color de la sombra. El valor por defecto es negro semitransparente.

Shape y personalización de bordes

Con la propiedad shape decides la forma del borde del Card. Puedes usar:

  • RoundedRectangleBorder → esquinas redondeadas (la más común)
  • CircleBorder → forma circular completa
  • StadiumBorder → bordes tipo "pill" en los extremos

Si vienes de Android, verás que es casi idéntico al antiguo CardView de la librería de soporte.

Margin, padding y clipBehavior

  • margin: espacio externo alrededor del Card, que lo separa de los demás elementos.
  • padding: normalmente no se define directamente en el Card, sino en el widget contenedor interno (un Padding o Container). Así tienes más control sobre el espaciado.
  • clipBehavior: controla si los widgets internos pueden desbordarse más allá de los bordes del Card. Si tienes una imagen que sobresale de las esquinas redondeadas, añadir clipBehavior: Clip.antiAlias lo resuelve de inmediato.

child: cómo organizar varios widgets dentro de un Card

Un Card solo acepta un único child. Si necesitas colocar varios elementos dentro, debes usar un widget contenedor que admita múltiples hijos. Las opciones más habituales son:

  • Column → para apilar widgets verticalmente
  • Row → para alinear widgets en horizontal
  • ListTile → para mostrar información estructurada estilo lista
  • Container → para tener control total del layout y el espaciado

Recuerda: un Card solo acepta un child. Es lo primero que hay que interiorizar cuando se empieza a trabajar con este widget.

Cómo construir un Card básico en Flutter paso a paso

Para crear un Card en Flutter, simplemente instancias el widget:

Card()

Como puedes suponer, un Card vacío no renderiza nada visible. Necesitas definir al menos su propiedad child para que tenga contenido:

Card(
  child: Center(
    child: Text("Hola Card"),
  ),
)

Con esto ya tienes un Card básico funcional: un texto centrado dentro de una tarjeta con sombra y bordes redondeados por defecto.

Añadir Column o Row para múltiples elementos

Cuando necesitas combinar imagen, texto y un botón —que es la estructura más frecuente—, una Column es tu mejor aliada. Aquí un ejemplo completo con esos tres elementos:

Card(
  child: Column(
    children: [
      Image.asset('assets/codeigniter.png'),
      Text("Curso en CodeIgniter"),
      IconButton(
        icon: Icon(Icons.access_alarms),
        onPressed: () {},
      )
    ],
  ),
)

Fíjate que el Card tiene un solo child —la Column— y es ella quien gestiona todos los widgets internos. Este patrón es el más habitual al trabajar con tarjetas de contenido.

Definir imágenes en nuestros Card widget

Aunque con esto tenemos prácticamente nada, ya que un contenedor vacío no nos sirve de nada; podemos agregar todos los elementos que queramos, o cualquier otro widget mediante la propiedad child, pero SOLO podemos agregar UN WIDGET, y nada más:

Card(
  child: Center(
	child: MaterialButton(
  	minWidth: 200.0,
  	height: 40.0,
  	onPressed: () {},
  	color: Colors.lightBlue,
  	child: Text('Material Button',
      	style: TextStyle(color: Colors.white)),
	),
  ),
),

Como puedes ver, aquí tenemos varias propiedades importante, para indicar el tamaño mediante los width y el height además de que estamos agregando un botón con un texto tal cual vimos en la entrada anterior de Los widgets de los botones en Flutter: Raised, Flat, Material, Icon y Floating Action

Flutter Card con un botón

Aunque podemos agregar cualquier tipo de widget, y hay algunos realmente que nos vienen estupendos al momento de trabajar con los Card en Flutter.

Cómo ves, algo bastante aburrido y pobre, pero por supuesto podemos usar cualquier otro widget y existen widgets que nos ayudarán en esta tarea, por ejemplo uno de tipo columna con el cual podemos agregar muchos otros widgets:

body: Card(
  child: Center(
	child: Column(
  	children: <Widget>[
    	Image.asset('assets/codeigniter.png'),
    	Text("Curso en CodeIgniter"),
    	IconButton(
      	icon: Icon(Icons.access_alarms),
      	tooltip: "Mensaje",
    	),
  	],
	),
  ),
),

Como puedes apreciar en este ejemplo, lo ideal es combinar widgets; tomar las características de un widget y de esta manera sumarlas en conjunto; como te indicamos antes, los Card en Flutter solo pueden contener un widgets; por lo tanto es casi obligatorio emplear otro widgets como el de Column que nos permite agregar los elementos que queramos.

Card con texto imágen y botón en un column

https://kodestat.gitbook.io/flutter/37-flutter-using-cards

Padding y márgenes en los Card de Flutter

Por supuesto, como cualquier contenedor o layout que nosotros empleamos en nuestras aplicaciones, necesita un margen; también existen propiedades para tal motivo, para eso podemos emplear la propiedad padding como te mostramos a continuación:

Container(
 padding: new EdgeInsets.all(32.0),
 height: 350,
 child: Card(
   color: Color.fromRGBO(84, 197, 248, 1),
   child: Center(
     child: Column(
       children: <Widget>[
         Image.asset('assets/codeigniter.png'),
         Text("Curso en CodeIgniter"),
         IconButton(
           icon: Icon(Icons.access_alarms),
           tooltip: "Mensaje",
         ),
       ],
     ),
   ),
 ),
)

Aquí en esta oportunidad variamos algunas cosas; primero definimos otro tipo de layout, que viene siendo el container que como puedes suponer de su nombre, permite contener un elemento mediante su atributo child; entre esos elementos colocamos nuestro Card; y no solo eso, en este mismo container definimos nuestro espaciado interno mediante la propiedad padding; también aprovechamos y definimos el height para que no ocupe toda la pantalla:

Card con padding

Bordes redondeados para los Card

Si vienes del desarrollo nativo en Android, sabrás que uno de los principales elementos característicos del CardView es precisamente que cuentan con los border redondeados por defecto; aquí también podemos crear nuestros bordes redondeados sobre nuestros Card mediante la propiedad shape:

Container(
 padding: new EdgeInsets.all(32.0),
 height: 350,
 child: Card(
   shape: RoundedRectangleBorder(
   borderRadius: BorderRadius.circular(20.0),
 ),
   color: Color.fromRGBO(84, 197, 248, 1),
   child: Center(
     child: Column(
       children: <Widget>[
         Image.asset('assets/codeigniter.png'),
         Text("Curso en CodeIgniter"),
         IconButton(
           icon: Icon(Icons.access_alarms),
           tooltip: "Mensaje",
         ),
       ],
     ),
   ),
 ),
),
Card con esquinas más redondeadas

Finalmente te dejo por aquí el código completo de nuestra aplicación así como el enlace a la documentación oficial:

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   // TODO: implement build
   return MaterialApp(
     home: Scaffold(
       //  backgroundColor: Color.fromRGBO(84, 197, 248, 1),
       appBar: AppBar(
         title: Text('Card'),
       ),
       body: Container(
         padding: new EdgeInsets.all(32.0),
         height: 350,
         child: Card(
           shape: RoundedRectangleBorder(
           borderRadius: BorderRadius.circular(20.0),
         ),
           color: Color.fromRGBO(84, 197, 248, 1),
           child: Center(
             child: Column(
               children: <Widget>[
                 Image.asset('assets/codeigniter.png'),
                 Text("Curso en CodeIgniter"),
                 IconButton(
                   icon: Icon(Icons.access_alarms),
                   tooltip: "Mensaje",
                 ),
               ],
             ),
           ),
         ),
       ),
     ),
   );
 }
}

Crear nuestra primera tarjeta o Card en Flutter

Las Card en Flutter, que las puedes traducir algo así como tarjetas, son un elemento fundamental en el Material Design y nos permiten crear aplicaciones con un muy buen estilo, las Cards son unos de los elementos más llamativos en el Material Design y su uso es muy sencillo, permite adaptar o colocar dentro de la misma cualquier tipo de Widgets y en esta entrada te daremos varios ejemplos de cómo podemos emplearla.

Queremos hacer una tarjeta clásica, una imagen, un bloque de texto y una imagen; la típica que empleamos para el Material Design:

Tarjeta Card clásica del Material Design con Fultter

Nada raro por los momentos; vamos a ir comenzando poco a poco y vamos desde lo más básico hasta llegar a lo que queremos conseguir; para lograr este objetivo tenemos que emplear un tipo de widget conocido como Card y lo primero que necesitamos es una carta para eso la clase widget en Flutter llamada Card:

Card()

Pero así no más no nos va a funcionar, necesitamos definir una propiedad llamada child que como ocurre con muchos otros tipos de widgets contenedores, debemos de indicarle el contenido; así que de momento quiero una tarjeta con un texto, así de simple:

return Card(child: Text("Hola Mundo"));

Obtenemos:

Tarjeta con texto

Agregando Texto e imágenes en el Widget Card

Pero cómo ver ahora no podemos agregar nuestra imagen promocional, porqué la propiedad child solamente acepta un y solo un Widget; en estos casos tenemos que aplicar otro tipo de contenedor que acepte una lista de widgets; el Colunm nos viene perfectamente en esta labor, dicho widget también lo tocamos en entradas anteriores; ahora nuestro código queda de la siguiente forma; de tal forma, que ahora sí podemos agregar nuestra imagen:

Card(
       child: Column(
     children: <Widget>[
       Image.asset('assets/curso.png'),
       Text("Hola Mundo"),
     ],
   ));

Obtenemos:

Tarjeta Card clásica del Material Design con Fultter sin espacio

Y por esto les comentaba anteriormente, que dentro del Card o tarjeta podemos agregar lo que queramos, ya que es un simple contenedor con un diseño predefinidos.

Ok vamos mucho mejor, ya agregando un par de widgets más, un contenedor en donde colocamos una lista de widgets y pasamos nuestra imagen que está guardada en la carpeta assets y un texto, logramos la presentación anterior; pero todavía podemos sacarle más el jugo a nuestra tarjeta; como ves, nuestro texto está muy pegado al contenedor y no se ve del todo bien; y ahora nuestro contenedor perdió las esquinas redondeadas:

Card(
       child: Column(
     children: <Widget>[
       Image.asset('assets/curso.png'),
       Container(
         padding: EdgeInsets.all(10),
         child: Text("Hola Mundo"),
       )
     ],
   ));
Tarjeta Card clásica del Material Design con Fultter

Cambiar los border de los Card en Flutter

Ya con esto logramos que nuestro texto tenga más espacio en el texto; para eso empleamos un widget contenedor y a posterior aplicamos un margen interno o padding, ahora vamos a solucionar el problema de las esquinas puntiagudas; básicamente tenemos que emplear clipBehavior: Clip.antiAlias, en nuestra tarjeta, de tal manera que estamos configurando para que nuestra tarjeta o carta elimine todo lo que sobresale de la misma:

   return Card(
       clipBehavior: Clip.antiAlias,
       child: Column(
         children: <Widget>[
           Image.asset('assets/curso.png'),
           Container(
             padding: EdgeInsets.all(10),
             child: Text("Hola Mundo"),
           )
         ],
       ));
tarjeta con esquinas redondeadas

Para variar la redondez de las esquinas, puedes hacer lo siguiente:

Card(
       clipBehavior: Clip.antiAlias,
       shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
       child: Column(
         children: <Widget>[
           Image.asset('assets/curso.png'),
           Container(
             padding: EdgeInsets.all(10),
             child: Text("Hola Mundo"),
           )
         ],
       ));
modificación tarjeta card con esquinas muy redondeadas

Cartas con botones

Aunque vamos a mostrarte también aquí que puedes hacer; para este ejemplo empleamos unos cuantos widgets más como el de ListTile que nos permite crear un item de lista, ideal para mostrar información con el estilo presentado para esta imagen; además de que empleamos el elevation para variar la sombra; en definitiva, lo importante, para colocar botones, empleamos los Row para colocar botones uno del lado del otro y todo esto en una columna, para mostrar en una columna todo el contenido u otros widgets:

Card(
     elevation: 5,
     shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
     child: Column(
       children: <Widget>[
         ListTile(
          // leading: Icon(Icons.photo_album, color: Colors.blue),
           title: Text("Título"),
           subtitle: Text(
               " aqui estamos trabajando en la tarjeta de flutter y bla bla"),
         ),
         Row(
           mainAxisAlignment: MainAxisAlignment.end,
           children: <Widget>[
             FlatButton(
                 child: Text("Ok"),
                 onPressed: () {
                   Text("Ok");
                 }),
             FlatButton(
                 child: Text("Cancelar"),
                 onPressed: () {
                   Text("Cancelar");
                 })
           ],
         )
       ],
     ),
   );
Tarjeta Card con botones

Card con imagen, texto y botón

Un diseño típico para un artículo, un perfil o un producto:

Card(
 elevation: 8,
 shadowColor: Colors.black54,
 child: Padding(
   padding: EdgeInsets.all(16),
   child: Column(
     children: [
       Image.asset('assets/card-sample.png'),
       SizedBox(height: 12),
       Text("Ejemplo de Card Completo"),
       ElevatedButton(
         onPressed: () {},
         child: Text("Acción"),
       )
     ],
   ),
 ),
)

Card tipo ListTile (estilo Material.io)

Práctico para notificaciones, configuraciones o listas:

Card(
 child: ListTile(
   leading: Icon(Icons.info),
   title: Text("Título del Card"),
   subtitle: Text("Texto secundario"),
 ),
)

Cards táctiles: InkWell y acciones al presionar

Para pantallas de catálogo o navegación:

Card(
 child: InkWell(
   onTap: () {},
   child: Padding(
     padding: EdgeInsets.all(16),
     child: Text("Tócame"),
   ),
 ),
)

Variantes actuales del Card en Material 3

Ideal para bloques de contenido con fondo sólido.

Card.filled(
 child: Padding(
   padding: EdgeInsets.all(16),
   child: Text("Filled Card"),
 ),
)

Outlined Card

Perfecto para tarjetas minimalistas sin sombra.

Card.outlined(
 child: Padding(
   padding: EdgeInsets.all(16),
   child: Text("Outlined Card"),
 ),
)

Errores comunes al trabajar con el widget Card

  • Crear un Card vacío y pensar que "no funciona".
    • Sin child, no verás absolutamente nada en pantalla. Es el error más frecuente al empezar.
  • Usar una elevation demasiado alta.
    • Valores superiores a 12 hacen que el Card parezca artificialmente flotante. Queda poco profesional.
  • No añadir padding interno.
    • El contenido queda pegado a los bordes y visualmente se ve muy descuidado. Siempre usa al menos EdgeInsets.all(16) como padding interno mínimo.
  • Widgets que sobrepasan los bordes sin clipBehavior.
    • Las imágenes son las principales culpables. Añade clipBehavior: Clip.antiAlias al Card para que el recorte respete las esquinas redondeadas.

Imágenes dentro del widget Card

El Card acepta cualquier widget como child, incluyendo imágenes. Sin embargo, como solo admite un único hijo, si quieres combinar imagen con texto u otros elementos necesitas un widget contenedor intermedio.

Cards con botones usando ListTile y Row

Card(
  elevation: 5,
  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
  child: Column(
    children: <Widget>[
      ListTile(
        title: Text("Título"),
        subtitle: Text("Aquí estamos trabajando en la tarjeta de Flutter"),
      ),
      Row(
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          TextButton(
            child: Text("Ok"),
            onPressed: () {},
          ),
          TextButton(
            child: Text("Cancelar"),
            onPressed: () {},
          )
        ],
      )
    ],
  ),
)

El SizedBox con height: 12 actúa como separador entre la imagen y el texto, aportando ese "aire" que hace que el diseño respire. Es un patrón muy sencillo pero muy efectivo.

Nota: FlatButton fue deprecado en Flutter 2.0. El reemplazo oficial es TextButton, que mantiene el mismo comportamiento pero se alinea con las guías actuales de Material Design.

Cards táctiles: InkWell y acciones al presionar

Card(
 child: InkWell(
   onTap: () {},
   child: Padding(
     padding: EdgeInsets.all(16),
     child: Text("Tócame"),
   ),
 ),
)

También puedes usar GestureDetector si prefieres detectar gestos más específicos (doble toque, deslizamiento, etc.), aunque para la mayoría de casos InkWell es la opción más idiomática en Flutter.

Variantes del Card en Material 3

A partir de Material 3, el widget Card en Flutter incluye tres variantes oficiales que cubren los casos de uso más comunes sin necesidad de configuración adicional:

Card.filled

Ideal para bloques de contenido que deben destacar con un fondo sólido, sin sombra. Usa el color de superficie del tema activo:

Card.filled(
 child: Padding(
   padding: EdgeInsets.all(16),
   child: Text("Filled Card"),
 ),
)

Card.outlined

Card.outlined(
 child: Padding(
   padding: EdgeInsets.all(16),
   child: Text("Outlined Card"),
 ),
)

En resumen, las tres variantes de Material 3 son:

  • Card() → con sombra (elevated, la variante clásica)
  • Card.filled() → fondo sólido sin sombra
  • Card.outlined() → solo borde, sin sombra ni relleno prominente

Buenas prácticas para diseñar tarjetas limpias y profesionales

Jerarquía y organización del contenido

Una buena estructura visual para el contenido de un Card es la siguiente progresión:

Imagen → Título → Descripción → Acción

Esta secuencia guía el ojo del usuario de forma natural: primero capta la atención visual, luego la contextualizan el título y la descripción, y finalmente la acción le dice qué puede hacer.

Jerarquía visual y tipografía

  • Usa sombras suaves: valores de elevation entre 2 y 6 son suficientes en la mayoría de casos.
  • No mezcles demasiados estilos de texto dentro de una misma tarjeta: un título, un subtítulo y quizás una etiqueta o precio. Nada más.
  • Espaciado generoso: un mínimo de 16px de padding interno es la recomendación de Material Design. Por debajo de eso, el contenido se siente apretado.

Sombra, contraste y accesibilidad

  • Revisa el contraste entre el texto y el color de fondo del Card, especialmente si usas color personalizado. Herramientas como el Contrast Checker de WebAIM te ayudan a verificarlo.
  • Evita sombras muy densas: el Card puede parecer agresivo visualmente.
  • Mantén los bordes redondeados consistentes en toda la aplicación; mezclar radios distintos sin criterio rompe la cohesión visual del diseño.

Preguntas frecuentes sobre el widget Card en Flutter

  • ¿Cómo agrego varios widgets dentro de un Card?
    • Usando un Column, Row, ListTile o Container como child. Recuerda que el Card solo acepta un widget directamente.
  • ¿Cómo hago un Card táctil?
    • Rodéalo con InkWell (para el efecto ripple de Material Design) o con GestureDetector (para gestos más específicos).
  • ¿Qué diferencia hay entre Card, Card.filled y Card.outlined?
    • Son las tres variantes de Material 3. La primera tiene sombra (elevated), la segunda usa fondo sólido sin sombra, y la tercera solo muestra un borde sin sombra ni relleno prominente.
  • ¿Cómo cambio la forma del Card?
    • Con la propiedad shape. Por ejemplo: shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)).
  • ¿Cómo personalizo el color de fondo del Card?
    • Con la propiedad color: color: Colors.blue.shade50 o cualquier valor de tipo Color que necesites.
  • ¿Cómo evito que la imagen se desborde de los bordes redondeados?
    • Añade clipBehavior: Clip.antiAlias al Card. Eso recorta automáticamente cualquier contenido que sobresalga del borde redondeado.

Conclusión

El widget Card en Flutter es extremadamente versátil: puedes usarlo para listas, formularios, catálogos de productos, perfiles de usuario, paneles de configuración y prácticamente cualquier bloque de contenido que quieras presentar de forma ordenada y visualmente clara.

Con solo dominar sus propiedades principales —color, shape, elevation, shadowColor y clipBehavior— y combinarlo con Column, imágenes y botones, puedes construir interfaces limpias y profesionales que se adaptan perfectamente a cualquier tipo de aplicación.

Y lo mejor de todo: su comportamiento es consistente en Android, iOS y web. Una sola implementación, tres plataformas cubiertas.

El siguiente paso es explorar las variantes de Material 3 (Card.filled y Card.outlined) para darle un aspecto más moderno a tus interfaces sin apenas esfuerzo.

Siguiente widget: el widget Slider para definir rangos en Flutter.

Aprende a usar el widget Card en Flutter con ejemplos de código reales. Domina la elevation, el border radius, el color, el clipBehavior y las nuevas variantes Card.filled y Card.outlined de Material 3.


Únete a la comunidad de desarrolladores que han decidido dejar de picar código y empezar a construir productos reales. Recibe mis mejores trucos de arquitectura cada semana:

Acepto recibir anuncios de interes sobre este Blog.