Card 008 — Flutter Card Widget

Free copy-paste Card 008 for Flutter: a ready-to-use card widget with full Dart source code and a live preview. Works on mobile & desktop. No external packages.

  • Category: Cards
  • Platforms: mobile, desktop
  • Flutter SDK only — no external packages
  • Free to copy & use

How to use Card 008 in Flutter

Copy the Dart code below into a new file in your Flutter project (for example lib/widgets/card_008.dart) and use the widget anywhere in your widget tree.

Card 008 – Dart source code

import 'package:flutter/material.dart';

class Card008 extends StatefulWidget {
  const Card008({
    super.key,
    this.title = '3D Card',
    this.description =
        'Lorem ipsum dolor sit amet, consectetur adipisicing elit.',
    this.buttonText = 'SEE MORE',
    this.month = 'JUNE',
    this.day = '29',
    this.cyanColor = const Color(0xFF04C1FA),
    this.onTap,
  });

  final String title, description, buttonText, month, day;
  final Color cyanColor;
  final VoidCallback? onTap;

  @override
  State<Card008> createState() => _Card008State();
}

class _Card008State extends State<Card008>
    with SingleTickerProviderStateMixin {
  late final AnimationController _ctrl;
  late final Animation<double> _anim;
  bool _btnHover = false;

  @override
  void initState() {
    super.initState();
    _ctrl = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 1000),
    );
    _anim = CurvedAnimation(parent: _ctrl, curve: Curves.easeOutCubic);
  }

  @override
  void dispose() {
    _ctrl.dispose();
    super.dispose();
  }

  Widget _shift(double t, double x, double y, Widget child) =>
      Transform.translate(offset: Offset(x * t, y * t), child: child);

  @override
  Widget build(BuildContext context) {
    return MouseRegion(
      opaque: true,
      cursor: SystemMouseCursors.click,
      onEnter: (_) => _ctrl.forward(),
      onExit: (_) => _ctrl.reverse(),
      child: GestureDetector(
        behavior: HitTestBehavior.opaque,
        onTap: widget.onTap,
        child: AnimatedBuilder(
          animation: _anim,
          builder: (context, _) {
            final t = _anim.value;
            final m = Matrix4.identity()
              ..setEntry(3, 2, 0.0012)
              ..rotateX(-0.16 * t)
              ..rotateY(-0.32 * t);
            final c = widget.cyanColor;

            return Transform(
              alignment: Alignment.center,
              transform: m,
              child: Container(
                width: 290,
                clipBehavior: Clip.antiAlias,
                decoration: BoxDecoration(
                  color: const Color(0xFFF0F0F0),
                  border: Border.all(color: Colors.white, width: 3),
                  borderRadius: BorderRadius.circular(4),
                  boxShadow: [
                    BoxShadow(
                      color: Colors.black.withValues(alpha: 0.15 + 0.20 * t),
                      blurRadius: 18 + 20 * t,
                      offset: Offset(-8 * t, 12 + 18 * t),
                    ),
                  ],
                ),
                child: Stack(
                  clipBehavior: Clip.antiAlias,
                  children: [
                    Positioned.fill(
                      child: CustomPaint(
                        painter: _PerspectivePatternPainter(progress: t),
                      ),
                    ),
                    Column(
                      crossAxisAlignment: CrossAxisAlignment.stretch,
                      children: [
                        const SizedBox(height: 52),
                        Container(
                          padding: const EdgeInsets.fromLTRB(22, 48, 22, 22),
                          color: c.withValues(alpha: 0.76),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              _shift(
                                t,
                                4,
                                -2,
                                Text(
                                  widget.title,
                                  style: const TextStyle(
                                    color: Colors.white,
                                    fontSize: 24,
                                    fontWeight: FontWeight.w900,
                                  ),
                                ),
                              ),
                              const SizedBox(height: 10),
                              _shift(
                                t,
                                2,
                                -1,
                                Text(
                                  widget.description,
                                  style: const TextStyle(
                                    color: Color(0xFFF2F2F2),
                                    fontSize: 12,
                                    fontWeight: FontWeight.w600,
                                    height: 1.45,
                                  ),
                                ),
                              ),
                              const SizedBox(height: 16),
                              MouseRegion(
                                onEnter: (_) =>
                                    setState(() => _btnHover = true),
                                onExit: (_) =>
                                    setState(() => _btnHover = false),
                                child: AnimatedScale(
                                  scale: _btnHover ? 1.06 : 1.0,
                                  duration: const Duration(milliseconds: 1000),
                                  child: Container(
                                    decoration: BoxDecoration(
                                      color: Colors.white,
                                      boxShadow: [
                                        BoxShadow(
                                          color: Colors.black.withValues(
                                            alpha: 0.12,
                                          ),
                                          blurRadius: 8,
                                          offset: const Offset(0, 3),
                                        ),
                                      ],
                                    ),
                                    padding: const EdgeInsets.symmetric(
                                      horizontal: 14,
                                      vertical: 8,
                                    ),
                                    child: Text(
                                      widget.buttonText,
                                      style: TextStyle(
                                        color: c,
                                        fontSize: 10,
                                        fontWeight: FontWeight.w900,
                                        letterSpacing: 0.8,
                                      ),
                                    ),
                                  ),
                                ),
                              ),
                            ],
                          ),
                        ),
                      ],
                    ),
                    Positioned(
                      top: 20,
                      right: 20,
                      child: _shift(
                        t,
                        8,
                        -6,
                        Container(
                          width: 60,
                          height: 60,
                          decoration: BoxDecoration(
                            color: Colors.white,
                            border: Border.all(color: c, width: 1.5),
                            boxShadow: [
                              BoxShadow(
                                color: const Color(
                                  0xFF64646F,
                                ).withValues(alpha: 0.25 + 0.20 * t),
                                blurRadius: 10 + 12 * t,
                                offset: Offset(4 * t, 8 + 8 * t),
                              ),
                            ],
                          ),
                          child: Column(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              Text(
                                widget.month,
                                style: TextStyle(
                                  color: c,
                                  fontSize: 9,
                                  fontWeight: FontWeight.w800,
                                ),
                              ),
                              Text(
                                widget.day,
                                style: TextStyle(
                                  color: c,
                                  fontSize: 20,
                                  fontWeight: FontWeight.w900,
                                  height: 1.1,
                                ),
                              ),
                            ],
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

class _PerspectivePatternPainter extends CustomPainter {
  const _PerspectivePatternPainter({this.progress = 0.0});

  final double progress;

  @override
  void paint(Canvas canvas, Size size) {
    canvas.clipRect(Offset.zero & size);
    final paint = Paint()
      ..color = const Color(0xFFE2E2E2)
      ..strokeWidth = 2.0;
    final double shift = (progress * 30.0) % 24.0;
    for (double x = -size.height - 24; x < size.width + 24; x += 24.0) {
      canvas.drawLine(
        Offset(x + shift, 0),
        Offset(x + shift + size.height, size.height),
        paint,
      );
      canvas.drawLine(
        Offset(x - shift, size.height),
        Offset(x - shift + size.height, 0),
        paint,
      );
    }
  }

  @override
  bool shouldRepaint(_PerspectivePatternPainter oldDelegate) =>
      oldDelegate.progress != progress;
}

More Flutter Cards