Text Link
Inline underlined text link with a trailing icon. Polymorphic — renders a Next.js Link when href is provided, or a button when used with onClick. Used in the footer ('See my profile') and on the homepage testimonials toggle ('View more reviews').
Default (link mode)
Default icon is ArrowUpRight. Use this style for navigation — e.g. the footer's "Open to new roles — See my profile" row.
Open to new roles — See my profile
tsx
<TextLink href="/about">See my profile</TextLink>Toggle (button mode)
Omit href and pass onClick to render a button. Pair with ChevronDown and a rotate-180 transform on iconClassName for an expand/collapse affordance — exactly the pattern used by the mobile testimonials "View more reviews" toggle.
tsx
const [expanded, setExpanded] = useState(false)
<TextLink
icon={ChevronDown}
iconClassName={cn('transition-transform', expanded && 'rotate-180')}
onClick={() => setExpanded((v) => !v)}
aria-expanded={expanded}
>
{expanded ? 'View less' : 'View more reviews'}
</TextLink>Custom icon
Pass any Lucide icon via the icon prop.
See my profile (default ArrowUpRight)
tsx
<TextLink href="/work" icon={ArrowRight}>Browse all work</TextLink>
<TextLink href="/about">See my profile</TextLink>Props
| Prop | Type | Default | Description |
|---|---|---|---|
href | string | - | When provided, renders a Next.js Link. Omit to render a <button> (use with onClick). |
onClick | () => void | - | Click handler. Available when no href is provided (button mode). |
icon | LucideIcon | ArrowUpRight | Trailing icon. Defaults to ArrowUpRight; pass any Lucide icon (e.g. ChevronDown for expand affordances). |
iconClassName | string | - | Classes applied to the icon — useful for transforms like rotate-180 on toggles. |
className | string | - | Additional classes merged into the link/button root. |
children* | ReactNode | - | The link text. |
Import
tsx
import { TextLink } from '@/components/ui/TextLink'