Ora

How do you make a link button in Flutter?

Published in Flutter UI Navigation 7 mins read

To create a link button in Flutter, you combine a standard button widget (such as ElevatedButton, TextButton, or OutlinedButton) with the url_launcher package to programmatically open a URL. For a more direct, web-centric approach that allows control over how links open (e.g., in a new tab), the Link widget from the same url_launcher package is an excellent and powerful alternative.

Understanding Link Buttons in Flutter

A "link button" in Flutter functions like a traditional HTML hyperlink but is styled as a button. When a user taps it, instead of performing an in-app action, it typically navigates them to an external URL, opens an email client, initiates a phone call, or performs other URI-based actions. Flutter doesn't offer a specific LinkButton widget out-of-the-box, but achieving this functionality is straightforward using existing tools.

Method 1: Using url_launcher with Standard Buttons

This is the most common and flexible method, allowing you to wrap URL launching logic within the onPressed callback of any standard Flutter button.

1. Add the url_launcher Package

First, you need to add the url_launcher dependency to your pubspec.yaml file. Always use the latest stable version for best compatibility and features.

dependencies:
  flutter:
    sdk: flutter
  url_launcher: ^6.2.2 # Check pub.dev for the latest version

After adding the dependency, run flutter pub get in your terminal to fetch the package.

2. Import and Implement Launch Logic

Import the package into your Dart file and create an asynchronous function to handle the URL launching.

import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart'; // Import the url_launcher package

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Link Button',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: Scaffold(
        appBar: AppBar(title: const Text('Link Button Example')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ElevatedButton(
                onPressed: () => _launchURL('https://flutter.dev'),
                child: const Text('Visit Flutter Website'),
              ),
              const SizedBox(height: 20),
              TextButton(
                onPressed: () => _launchURL('mailto:[email protected]?subject=Help'),
                child: const Text('Email Support'),
              ),
              const SizedBox(height: 20),
              OutlinedButton(
                onPressed: () => _launchURL('tel:+15551234567'),
                child: const Text('Call Us'),
              ),
            ],
          ),
        ),
      ),
    );
  }

  // Asynchronous function to launch a URL
  Future<void> _launchURL(String urlString) async {
    final Uri url = Uri.parse(urlString);
    if (!await launchUrl(url)) {
      // Handle cases where the URL cannot be launched (e.g., no browser installed)
      throw Exception('Could not launch $url');
    }
  }
}
  • _launchURL(String urlString): This is an async function that takes a URL string, converts it into a Uri object, and then attempts to launch it using launchUrl().
  • Error Handling: It's crucial to include if (!await launchUrl(url)) to gracefully handle scenarios where the URI cannot be opened (e.g., no default browser, email client, or phone app is configured for the given scheme).

Method 2: Using the Link Widget for Direct Linking

For situations where you want a button-like element that acts as a true hyperlink, especially in web applications, the Link widget from the url_launcher package is the ideal solution. This widget directly implements the "Follow link Method" and allows you to "Set a link Target" (like blank or self), which is useful for controlling browser behavior.

The Link widget simplifies creating clickable elements that open a URI, abstracting away some of the direct url_launcher calls.

1. Basic Link Widget Usage

import 'package:flutter/material.dart';
import 'package:url_launcher/link.dart'; // Specifically import the Link widget

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Link Widget',
      theme: ThemeData(primarySwatch: Colors.green),
      home: Scaffold(
        appBar: AppBar(title: const Text('Link Widget Example')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Link(
                uri: Uri.parse('https://pub.dev'),
                target: LinkTarget.blank, // Opens in a new tab/window
                builder: (BuildContext context, FollowLink? followLink) {
                  return ElevatedButton(
                    onPressed: followLink, // This calls the "Follow link Method"
                    child: const Text('Go to Pub.dev (New Tab)'),
                  );
                },
              ),
              const SizedBox(height: 20),
              Link(
                uri: Uri.parse('https://docs.flutter.dev'),
                target: LinkTarget.self, // Opens in the same tab/window (if applicable)
                builder: (BuildContext context, FollowLink? followLink) {
                  return TextButton(
                    onPressed: followLink, // This calls the "Follow link Method"
                    child: const Text('Flutter Docs (Same Tab)'),
                  );
                },
              ),
              const SizedBox(height: 20),
              Link(
                uri: Uri.parse('https://google.com'),
                builder: (BuildContext context, FollowLink? followLink) {
                  return OutlinedButton(
                    onPressed: followLink, // Default target is self
                    child: const Text('Google (Default behavior)'),
                  );
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}
  • Link(uri: ...): This property specifies the Uniform Resource Identifier (URI) that the link should open.
  • builder: This required property takes a BuildContext and a FollowLink? followLink callback. You wrap your desired clickable widget (e.g., ElevatedButton, TextButton, or even a Text widget) inside this builder.
  • FollowLink? followLink: This is the callback function provided by the Link widget's builder. You assign this callback directly to your button's onPressed property. This followLink acts as the "Follow link Method" that activates the navigation to the uri.
  • target: LinkTarget.blank / LinkTarget.self: This property directly corresponds to the ability to "Set a link Target" as described.
    • LinkTarget.blank: When used in a web context, this instructs the browser to open the URI in a new tab or window. On other platforms, it typically behaves similarly to LinkTarget.self.
    • LinkTarget.self: Instructs the platform to open the URI in the same tab or window, effectively navigating away from the current view. This is the default behavior if target is not explicitly set.

When to Choose Each Method

Feature/Consideration url_launcher with Standard Buttons (onPressed) Link Widget
Control Full control over onPressed logic (e.g., custom logging, advanced validation before launch). More declarative, less direct control over launch logic; focused on standard linking.
Simplicity Slightly more boilerplate code for simple URI launching. Simpler for basic URI launching, especially on the web due to target support.
Web target options Requires manual implementation if _blank, _self behavior is needed (e.g., by checking platform). Built-in target property (LinkTarget.blank/self) for direct control.
Flexibility Highly flexible for any URI type (HTTP, HTTPS, tel, mailto, custom schemes). Primarily designed for HTTP/HTTPS URIs with target options, but supports others.
Use Case Ideal for complex actions or when a button's primary role is an action leading to a link. Best for visual elements that are direct hyperlinks.

Styling Your Link Buttons

You can style your link buttons using the standard Flutter button styling properties.

  • ElevatedButton: Customize using style property with ElevatedButton.styleFrom() or theme data (Theme.of(context).elevatedButtonTheme).
  • TextButton: Customize using style property with TextButton.styleFrom() or theme data (Theme.of(context).textButtonTheme). TextButton is often a good choice for mimicking traditional text-based hyperlinks due to its flat appearance.
  • OutlinedButton: Customize using style property with OutlinedButton.styleFrom() or theme data (Theme.of(context).outlinedButtonTheme).

To make a TextButton look more like a classic web link, you might set its color to blue and add an underline:

TextButton(
  onPressed: () => _launchURL('https://example.com'),
  style: TextButton.styleFrom(
    foregroundColor: Colors.blue, // Sets the text color to blue
    textStyle: const TextStyle(decoration: TextDecoration.underline), // Adds an underline
  ),
  child: const Text('Example Website Link'),
)

Best Practices for Link Buttons

  • User Feedback: Ensure your buttons provide visual feedback when tapped (e.g., default ripple effect) to indicate interactivity.
  • Accessibility: Use clear, descriptive text for your button labels so users know where the link will take them.
  • Error Handling: Always include if (!await launchUrl(url)) or similar checks to manage cases where a URL cannot be launched.
  • Permissions: While standard web URLs generally don't require specific permissions, certain URI schemes (like tel:, sms:, or custom schemes) might need declarations in AndroidManifest.xml (Android) or Info.plist (iOS) to function correctly.
  • URL Encoding: Always ensure your URLs are correctly encoded, especially if they contain special characters or spaces. Uri.parse() handles basic encoding, but complex cases might require Uri.encodeComponent().

By leveraging Flutter's versatile widget system and the powerful url_launcher package, you can create effective and user-friendly link buttons for various navigation needs.