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 anasync
function that takes a URL string, converts it into aUri
object, and then attempts to launch it usinglaunchUrl()
.- 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 aBuildContext
and aFollowLink? followLink
callback. You wrap your desired clickable widget (e.g.,ElevatedButton
,TextButton
, or even aText
widget) inside this builder.FollowLink? followLink
: This is the callback function provided by theLink
widget'sbuilder
. You assign this callback directly to your button'sonPressed
property. ThisfollowLink
acts as the "Follow link Method" that activates the navigation to theuri
.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 toLinkTarget.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 iftarget
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 usingstyle
property withElevatedButton.styleFrom()
or theme data (Theme.of(context).elevatedButtonTheme
).TextButton
: Customize usingstyle
property withTextButton.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 usingstyle
property withOutlinedButton.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 inAndroidManifest.xml
(Android) orInfo.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 requireUri.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.