Anchor

An anchor is a primitive for building custom links.
Anchor is for building non-text links, such as a card. It comes with minimal styling. If you're using a link within text, use the purpose-built link component. For links that appear as buttons, use the existing link button component.

Installation

Package installation information
Installyarn add @atlaskit/primitives
SourceBitbucket.org, (opens new window)
npm@atlaskit/primitives, (opens new window)
Bundleunpkg.com, (opens new window)

Anchor is a primitive for building custom links with Atlassian Design System styling, routing support, and built-in event tracking. It renders an anchor <a> element.

Default

Anchor is unstyled besides a default underline and consistent Atlassian Design System focus styles.

If you are using the CSS reset, anchor will also inherit some global styles.

import React from 'react'; import { Anchor } from '@atlaskit/primitives/compiled/anchor'; export default function Default(): React.JSX.Element { return <Anchor href="/components/primitives/overview">Anchor</Anchor>; }

Basic styling

Anchor can be styled further using the design system styling API using cssMap.

Evolving Button: Open beta to GAOn track, (opens new window)
import React from 'react'; import { cssMap } from '@atlaskit/css'; import Image from '@atlaskit/image'; import Lozenge from '@atlaskit/lozenge/lozenge'; import { Anchor } from '@atlaskit/primitives/compiled/anchor'; import { Box } from '@atlaskit/primitives/compiled/box'; import { token } from '@atlaskit/tokens'; import ButtonIcon from '../../images/button.png'; const styles = cssMap({ anchor: { color: token('color.link'), backgroundColor: token('elevation.surface'), textDecoration: 'none', borderWidth: token('border.width'), borderStyle: 'solid', borderColor: token('color.border'), borderRadius: token('radius.small'), display: 'inline-flex', alignItems: 'center', gap: token('space.100'), paddingInline: token('space.050'), paddingBlock: token('space.025'), '&:hover': { backgroundColor: token('elevation.surface.hovered'), textDecoration: 'none', }, '&:active': { color: token('color.link.pressed'), backgroundColor: token('elevation.surface.pressed'), }, '&:visited': { color: token('color.link.visited'), }, }, iconContainer: { width: '16px', display: 'flex', }, }); export default function Basic(): React.JSX.Element { return ( <Anchor href="https://www.atlassian.com/software/atlas" interactionName="atlas-link" xcss={styles.anchor} target="_blank" rel="noopener noreferrer" > <Box xcss={styles.iconContainer}> <Image src={ButtonIcon} alt="" /> </Box> Evolving Button: Open beta to GA <Lozenge appearance="success">On track</Lozenge> </Anchor> ); }

Advanced styling

Use a combination of cssMap and other primitives for more complex designs.

Pick up where you left off

Anchor primitive is now in beta!

Design System Team
Visited 1 hour ago

Impact & release planning

Design System Team
Visited 1 day ago

How to implement dark mode

Design System Team
Visited 12 May 2024

New Bitbucket pull requests

Bitbucket Cloud
Visited 10 May 2024
import React from 'react'; import { cssMap } from '@atlaskit/css'; import Heading from '@atlaskit/heading/heading'; import type { IconProps } from '@atlaskit/icon/types'; import BlogObjectTile from '@atlaskit/object/tile/blog'; import ImprovementObjectTile from '@atlaskit/object/tile/improvement'; import PageObjectTile from '@atlaskit/object/tile/page'; import { Anchor } from '@atlaskit/primitives/compiled/anchor'; import { Box } from '@atlaskit/primitives/compiled/box'; import { Grid } from '@atlaskit/primitives/compiled/grid'; import { Inline } from '@atlaskit/primitives/compiled/inline'; import { Stack } from '@atlaskit/primitives/compiled/stack'; import { Text } from '@atlaskit/primitives/compiled/text'; import { token } from '@atlaskit/tokens'; const BlogIcon = () => <BlogObjectTile size="small" />; const PageIcon = () => <PageObjectTile size="small" label="" />; const ImprovementIcon = () => <ImprovementObjectTile size="small" label="" />; const styles = cssMap({ anchor: { color: token('color.text'), backgroundColor: token('elevation.surface'), paddingBlockStart: token('space.200'), paddingInlineEnd: token('space.200'), paddingBlockEnd: token('space.200'), paddingInlineStart: token('space.200'), textDecoration: 'none', borderColor: token('color.border'), borderStyle: 'solid', borderWidth: token('border.width'), borderRadius: token('radius.small'), '&:hover': { backgroundColor: token('elevation.surface.hovered'), textDecoration: 'none', }, '&:active': { backgroundColor: token('elevation.surface.pressed'), }, }, iconContainer: { width: '24px', display: 'flex', }, grid: { '@media (min-width: 48rem)': { gridTemplateColumns: '1fr 1fr', }, rowGap: token('space.100'), columnGap: token('space.100'), gridTemplateColumns: '1fr', }, }); type PageLinkProps = { href: string; title: string; space: string; lastVisited: string; icon: React.ComponentType<IconProps>; }; const PageLink = ({ href, title, space, lastVisited, icon: Icon }: PageLinkProps) => { return ( <Anchor href={href} xcss={styles.anchor}> <Stack space="space.100"> <Inline space="space.150" alignBlock="center"> <Box xcss={styles.iconContainer}> <Icon label="" /> </Box> <Stack> <Heading as="h3" size="small"> {title} </Heading> <Text color="color.text.subtle" size="small"> {space} </Text> </Stack> </Inline> <Text color="color.text.subtle" size="small"> Visited {lastVisited} </Text> </Stack> </Anchor> ); }; export default function Styled(): React.JSX.Element { return ( <Stack space="space.200"> <Heading as="h2" size="small"> Pick up where you left off </Heading> <Grid xcss={styles.grid}> <PageLink href="/components/primitives/overview" icon={BlogIcon} title="Anchor primitive is now in beta!" space="Design System Team" lastVisited="1 hour ago" /> <PageLink href="/components/primitives/overview" icon={PageIcon} title="Impact & release planning" space="Design System Team" lastVisited="1 day ago" /> <PageLink href="/components/primitives/overview" icon={PageIcon} title="How to implement dark mode" space="Design System Team" lastVisited="12 May 2024" /> <PageLink href="/components/primitives/overview" icon={ImprovementIcon} title="New Bitbucket pull requests" space="Bitbucket Cloud" lastVisited="10 May 2024" /> </Grid> </Stack> ); }

HTML attributes

Anchor can pass all valid anchor HTML attributes, (opens new window), such as rel or download, to the underlying <a> element.

import React from 'react'; import { Anchor } from '@atlaskit/primitives/compiled/anchor'; export default function AnchorHTMLAttributes(): React.JSX.Element { return ( <Anchor href="https://www.atlassian.com/" target="_blank" rel="noopener noreferrer"> Visit the Atlassian website </Anchor> ); }

Routing libraries often supply link components enhanced with routing support. You can configure this in the AppProvider context, and anchor will automatically use it.

This example shows a configuration for React Resource Router, (opens new window), however any routing library can be used.

Using this method, anchor accepts href as a string for standard usage. For advanced usage, an object can be passed.

Anchor will only render a router link if:

  • a link component is set in the app provider
  • it's not an external link (starting with http:// or https://)
  • it's not a non-HTTP-based link (e.g. emails, phone numbers, hash links etc.).

Event tracking

Anchor has utilities to make tracking events easier. Events won't be captured unless listeners are set up to handle them.

Track events for any analytics provider

Anchor comes with built-in Atlaskit analytics support using the Analytics next package, (opens new window), and fires events for available listeners. Currently this is only available for onClick.

Events always fire on the atlaskit channel. To fire events on other channels as well, use the provided analyticsEvent in onClick. To configure event data, use componentName (defaults to 'Anchor') and use analyticsContext to pass other metadata.

See the event data in the console.

import React, { useCallback } from 'react'; import AnalyticsListener from '@atlaskit/analytics-next/AnalyticsListener'; import type UIAnalyticsEvent from '@atlaskit/analytics-next/UIAnalyticsEvent'; import { Anchor } from '@atlaskit/primitives/compiled/anchor'; import { Inline } from '@atlaskit/primitives/compiled/inline'; export default function Analytics(): React.JSX.Element { const handleEvent = useCallback((event: UIAnalyticsEvent, channel?: string) => { console.log(`Channel: '${channel}'`, event); }, []); return ( <AnalyticsListener channel="*" onEvent={handleEvent}> <Inline space="space.100"> <Anchor href="/components/primitives/overview" target="_blank"> Default </Anchor> <Anchor href="/components/primitives/overview" target="_blank" onClick={(_, analyticsEvent) => { analyticsEvent.fire('my-channel'); }} > Fires on "my-channel" </Anchor> <Anchor href="/components/primitives/overview" target="_blank" componentName="MyButton" analyticsContext={{ color: 'blue', someId: 937458, }} > Customized event data </Anchor> </Inline> </AnalyticsListener> ); }

Track events for Atlassian internal services

GASv3 analytics

The Atlassian analytics bridge makes Atlaskit analytics events compatible with GASv3 (Global Analytics Service). This can also inject an actionSubjectId to the event if required.

See the event data in the console.

import React, { useCallback } from 'react'; import AnalyticsListener from '@atlaskit/analytics-next/AnalyticsListener'; import type UIAnalyticsEvent from '@atlaskit/analytics-next/UIAnalyticsEvent'; import { Anchor } from '@atlaskit/primitives/compiled/anchor'; import { ANALYTICS_BRIDGE_CHANNEL, extractAWCDataFromEvent, fireUIAnalytics, } from '@atlassian/analytics-bridge'; export default function AnalyticsGASv3(): React.JSX.Element { const handleEvent = useCallback((event: UIAnalyticsEvent, channel?: string) => { console.log(`Channel: '${channel}'`, extractAWCDataFromEvent(event)); }, []); const handleClick = useCallback( (_: React.MouseEvent<HTMLAnchorElement, MouseEvent>, analyticsEvent: UIAnalyticsEvent) => { fireUIAnalytics(analyticsEvent, 'theActionSubjectId'); }, [], ); return ( <AnalyticsListener channel={ANALYTICS_BRIDGE_CHANNEL} onEvent={handleEvent}> <Anchor href="/components/primitives/overview" target="_blank" onClick={handleClick} analyticsContext={{ attributes: { color: 'blue', someId: 937458, }, }} > Fire GASv3 compatible event </Anchor> </AnalyticsListener> ); }

React UFO press interactions

By default, anchor fires React UFO (Unified Frontend Observability) press interactions, (opens new window) for available listeners. This helps Atlassian measure performance and reliability. You can provide more detail using the interactionName prop.

Your projects

import React from 'react'; import { cssMap } from '@atlaskit/css'; import __noop from '@atlaskit/ds-lib/noop'; import { FlagsProvider } from '@atlaskit/flag/flags-provider'; import { useFlags } from '@atlaskit/flag/use-flags'; import Heading from '@atlaskit/heading/heading'; import InformationIcon from '@atlaskit/icon/core/status-information'; import Image from '@atlaskit/image'; import InteractionContext from '@atlaskit/interaction-context'; import { Anchor } from '@atlaskit/primitives/compiled/anchor'; import { Box } from '@atlaskit/primitives/compiled/box'; import { Flex } from '@atlaskit/primitives/compiled/flex'; import { Inline } from '@atlaskit/primitives/compiled/inline'; import { Stack } from '@atlaskit/primitives/compiled/stack'; import { token } from '@atlaskit/tokens'; import ButtonIcon from '../../images/button.png'; import ThemesIcon from '../../images/themes.png'; import WatermelonIcon from '../../images/watermelon.png'; const iconSpacingStyles = cssMap({ space050: { paddingBlock: token('space.050'), paddingInline: token('space.050'), }, }); const styles = cssMap({ anchor: { color: token('color.text'), textDecoration: 'none', '&:hover': { color: token('color.text'), textDecoration: 'underline', }, '&:active': { textDecoration: 'none', }, '&:visited': { color: token('color.link.visited'), }, }, iconContainer: { width: '24px', display: 'flex', }, }); type ProjectLinkProps = { children: string; icon: string; id: string; }; const ProjectLink = ({ children, icon, id }: ProjectLinkProps) => { return ( <Anchor href="#" xcss={styles.anchor} interactionName={`anchor-${id}`}> <Inline space="space.150" alignBlock="center"> <Box xcss={styles.iconContainer}> <Image src={icon} alt="" /> </Box> {children} </Inline> </Anchor> ); }; const Projects = () => { const { showFlag } = useFlags(); return ( <InteractionContext.Provider value={{ hold: __noop, tracePress: (name) => { console.log('Traced a press!', name); showFlag({ title: `Traced a press!`, description: name, icon: ( <Flex xcss={iconSpacingStyles.space050}> <InformationIcon label="Info" color={token('color.icon.information')} /> </Flex> ), isAutoDismiss: true, }); }, }} > <Stack space="space.200"> <Heading as="h2" size="small"> Your projects </Heading> <Stack space="space.100"> <ProjectLink icon={ButtonIcon} id="evolving-button"> Evolving Button: Open beta to GA </ProjectLink> <ProjectLink icon={ThemesIcon} id="increased-contrast-themes"> Increased contrast themes </ProjectLink> <ProjectLink icon={WatermelonIcon} id="typography"> ADS Typography </ProjectLink> </Stack> </Stack> </InteractionContext.Provider> ); }; export default function PressTracing(): React.JSX.Element { return ( <FlagsProvider> <Projects /> </FlagsProvider> ); }
Was this page helpful?
We use this feedback to improve our documentation.
© 2026 AtlassianTrademark, (opens new window)Privacy, (opens new window)License