NavigationLink
NavigationLink is a component that triggers navigation to a destination within a NavigationStack. It can navigate to another component or an external URL, and supports customizable transition animations.
NavigationLink is a component that triggers navigation to a destination within a NavigationStack. It can navigate to another component or an external URL, and supports customizable transition animations.
Examples
Navigate to a Component
Preview unavailable for this example in the static docs build.
Show code
<NavigationStack>
<VStack spacing={20}>
<NavigationLink destination={DetailPage}>
<Text>Go to Detail</Text>
</NavigationLink>
</VStack>
</NavigationStack>Navigate to External URL
Preview unavailable for this example in the static docs build.
Show code
<NavigationLink destination="https://example.com">External Link</NavigationLink>Action Sheet
Preview unavailable for this example in the static docs build.
Show code
<NavigationStack>
<VStack spacing={20}>
<NavigationLink destination={SheetContent} pageOptions={{ type: 'actionsheet' }}>
<Text>Show Action Sheet</Text>
</NavigationLink>
</VStack>
</NavigationStack>API
| Prop | Type | Required | Description |
|---|---|---|---|
destination | string | ComponentType | No | The destination component or URL to navigate to.
If a string is provided, it will navigate to that URL.
If a ComponentType is provided, it will navigate to that component within the NavigationStack. Default: undefined |
pageOptions | {
/**
* The type of page presentation.
*/
type?: IPageType
/**
* Transition configuration for page animation.
*
* @example
* ```tsx
* transition: {
* type: 'view-transition',
* viewTransitionName: 'shared-element'
* }
* ```
*/
transition?: ITransitionConfig
} | No | Options for configuring the page presentation. |
dismiss | boolean | No | A Boolean value that indicates whether to dismiss the current page.
When true, clicking the link will navigate back instead of forward. Default: false |
Inherits additional props from IBaseComponent.
Overview
NavigationLink is a component that triggers navigation to a destination within a NavigationStack. It can navigate to another component or an external URL, and supports customizable transition animations.
SwiftUI Correspondence: Similar to SwiftUI's NavigationLink.
Page Types
Standard Page
<NavigationLink
destination={DetailPage}
pageOptions={{ type: 'page' }}
>
<Text>Go to Detail</Text>
</NavigationLink>Transition Animations
NavigationLink supports customizable transition animations through the transition option in pageOptions.
Default Slide Animation
By default, pages use a slide animation:
<NavigationLink destination={DetailPage} pageOptions={{ type: 'page' }}>
<Button>Go to Detail</Button>
</NavigationLink>View Transitions with Shared Elements
Use View Transitions API for smooth shared element animations. This requires setting the same viewTransitionName on both source and target elements:
// Source element (in list)
<NavigationLink
destination={ProductDetail}
pageOptions={{
type: 'page',
transition: {
type: 'view-transition',
viewTransitionName: 'product-image'
}
}}
>
<div style={{ viewTransitionName: 'product-image' }}>
<Image src={product.thumbnail} />
<Text>{product.name}</Text>
</div>
</NavigationLink>
// Target element (in ProductDetail page)
function ProductDetail({ product }) {
return (
<StandardPage
id="product-detail"
navigationTitle={product.name}
transition={{
type: 'view-transition',
viewTransitionName: 'product-image'
}}
>
<Image
src={product.fullImage}
style={{ viewTransitionName: 'product-image' }}
/>
<Text>{product.description}</Text>
</StandardPage>
)
}Fade Transition
Use fade animation for modal-like presentations:
<NavigationLink
destination={ModalPage}
pageOptions={{
type: 'actionsheet',
transition: {
type: 'fade',
duration: 200
}
}}
>
<Button>Open Modal</Button>
</NavigationLink>Scale Transition
Use scale animation for popover-like presentations:
<NavigationLink
destination={PopoverPage}
pageOptions={{
type: 'actionsheet',
transition: {
type: 'scale',
duration: 250
}
}}
>
<Button>Show Popover</Button>
</NavigationLink>Custom Duration and Easing
<NavigationLink
destination={DetailPage}
pageOptions={{
type: 'page',
transition: {
type: 'slide',
duration: 400,
easing: 'cubic-bezier(0.4, 0, 0.2, 1)'
}
}}
>
<Button>Go to Detail</Button>
</NavigationLink>No Animation
<NavigationLink
destination={DetailPage}
pageOptions={{
type: 'page',
transition: {
type: 'none'
}
}}
>
<Button>Instant Navigation</Button>
</NavigationLink>Dismissing Pages
Use the dismiss prop to navigate back:
<NavigationLink dismiss>
<Button>Go Back</Button>
</NavigationLink>Or use it programmatically:
import { useNaviContext } from '@swiftuijs/ui'
function MyPage() {
const navi = useNaviContext()
return (
<StandardPage id="my-page">
<Button onClick={() => navi.dismiss()}>Go Back</Button>
</StandardPage>
)
}Props Reference
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
destination | string | ComponentType | ❌ | - | Destination component or URL to navigate to |
pageOptions | object | ❌ | - | Options for page presentation |
pageOptions.type | 'page' | 'actionsheet' | ❌ | 'page' | Type of page presentation |
pageOptions.transition | ITransitionConfig | ❌ | { type: 'slide' } | Transition configuration |
dismiss | boolean | ❌ | false | If true, navigates back instead of forward |
style | CSSProperties | ❌ | - | Custom CSS styles |
className | string | ❌ | - | Custom CSS class name |
children | ReactNode | ❌ | - | Content to display (usually a Button or Text) |
TransitionConfig
| Property | Type | Default | Description |
|---|---|---|---|
type | 'slide' | 'fade' | 'scale' | 'view-transition' | 'none' | 'slide' | Transition animation type |
direction | 'forwards' | 'backwards' | 'auto' | 'auto' | Transition direction (for slide type) |
viewTransitionName | string | - | View transition name for shared element animations |
duration | number | 300 | Animation duration in milliseconds |
easing | string | 'cubic-bezier(0.075, 0.82, 0.165, 1)' | CSS easing function |
Common Patterns
Master-Detail Navigation
// Master (List)
<StandardPage id="products" navigationTitle="Products">
<List>
{products.map(product => (
<NavigationLink
key={product.id}
destination={() => <ProductDetail product={product} />}
pageOptions={{ type: 'page' }}
>
<ProductRow product={product} />
</NavigationLink>
))}
</List>
</StandardPage>Shared Element Animation
// List item with shared element
<NavigationLink
destination={ProductDetail}
pageOptions={{
type: 'page',
transition: {
type: 'view-transition',
viewTransitionName: `product-${product.id}`
}
}}
>
<Card style={{ viewTransitionName: `product-${product.id}` }}>
<Image src={product.thumbnail} />
<Text>{product.name}</Text>
</Card>
</NavigationLink>
// Detail page with matching shared element
<StandardPage
id="product-detail"
transition={{
type: 'view-transition',
viewTransitionName: `product-${product.id}`
}}
>
<Card style={{ viewTransitionName: `product-${product.id}` }}>
<Image src={product.fullImage} />
<Text>{product.description}</Text>
</Card>
</StandardPage>Conditional Navigation
function ProductList({ products }) {
const handleProductClick = (product) => {
if (product.available) {
// Navigate to detail
} else {
// Show unavailable message
}
}
return (
<List>
{products.map(product => (
<NavigationLink
key={product.id}
destination={() => <ProductDetail product={product} />}
pageOptions={{ type: 'page' }}
>
<ProductRow
product={product}
onClick={handleProductClick}
/>
</NavigationLink>
))}
</List>
)
}Best Practices
- Use appropriate page types: Use
'page'for standard navigation,'actionsheet'for modal-like presentations - Choose the right transition: Use
'view-transition'for shared elements,'fade'for modals,'slide'for standard navigation - Set viewTransitionName consistently: When using View Transitions, ensure source and target elements use the same name
- Keep transitions smooth: Use appropriate durations (200-400ms) and easing functions
- Provide clear destinations: Always specify a valid
destinationprop - Use dismiss for back navigation: Use
dismissprop ornavi.dismiss()for going back
View Transitions API Notes
- View Transitions API requires browser support (Chrome 111+, Edge 111+)
- Falls back to CSS animations if not supported
- Shared element animations require matching
viewTransitionNameon both source and target - Works best with images, cards, and other visual elements
- Can be combined with other transition types for different elements
Related Components
- NavigationStack - Container for navigation
- StandardPage - Default page container
- Button - Often used as NavigationLink children
NavigationBar
NavigationBar is a component that displays a title, optional back button, and toolbar items. It's automatically used by StandardPage when a `navigationTitle` is provided, following iOS Human Interface Guidelines and SwiftUI's navigation bar design patterns.
NavigationSplitView
NavigationSplitView presents sidebar, optional content, and detail columns with a compact fallback mode.