@47ng/chakra-next
Opinionated design system for React, based on Chakra UI + Next.js.
Features
- Default theme with semantic tokens
- 100% TypeScript, transpiled to ESM (requires Next.js 12+)
- Components:
Installation
In your Next.js app:
$ npm install @47ng/chakra-next
Theme tools
To resolve theme tokens across color modes, use useColorModeToken
:
import { useColorModeToken } from '@47ng/chakra-next'
const fill = useColorModeToken('red.500', 'blue.500')
const shadow = useColorModeToken('md', 'dark-lg', 'shadows')
The following semantic tokens are provided:
- colors:
body
(follows the html/body/__next background color)text.dim
text.dimmer
text.dimmest
card.bg
- shadows:
card.shadow
(make card shadow darker in dark mode to stand out)
Components
Links
import { RouteLink, OutgoingLink, ButtonRouteLink } from '@47ng/chakra-next'
export default () => (
<>
{/* Integrate Next.js routes with Chakra styles */}
<RouteLink to="/login">Login</RouteLink>
{/* Use `as` for dynamic routes */}
<RouteLink to="/posts/[slug]" as="/posts/foo">Login</RouteLink>
{/* Make external links stand out */}
<OutgoingLink href="https://github.com" showExternalIcon>
GitHub
</RouteLink>
{/* For when a button looks better, still outputs an <a> tag */}
<ButtonRouteLink to="/logout">Logout</ButtonRouteLink>
</>
)
NavLinks
Use NavLink
when you want a link to have special styling depending on
the current page.
By default, NavLinks:
- Underline their text when active
- Are active when the current path starts with the link path
Example:
import { NavLink } from '@47ng/chakra-next'
export default () => (
<>
<NavLink to="/blog">Blog</NavLink>
</>
)
The link will be active for the following paths:
Path | Active |
---|---|
/home |
false |
/blog |
true |
/blog/ |
true |
/blog/foo |
true |
Custom active styles
import { NavLink } from '@47ng/chakra-next'
export default () => (
<>
<NavLink
to="/blog"
borderBottomWidth="3px"
borderBottomColor="transparent"
active={{ color: 'blue.500', borderBottomColor: 'blue.500' }}
>
Blog
</NavLink>
</>
)
Exact paths
Sometimes, you want the NavLink to be active only on exact route matches:
import { NavLink, navLinkMatch } from '@47ng/chakra-next'
export default () => (
<>
<NavLink to="/home" shouldBeActive={navLinkMatch.exact}>
Home
</NavLink>
</>
)
You can also have custom logic to determine whether a NavLink should be active:
import { NavLink, navLinkMatch } from '@47ng/chakra-next'
export default () => (
<>
<NavLink
to="/blog/[post]"
as="/blog/another-blog-post?active=true"
shouldBeActive={({ to, as, router }) =>
navLinkMatch.exact({ to, as, router }) &&
router?.query.active === 'true'
}
>
Another Blog Post
</NavLink>
</>
)
Redirect
Redirect
will change the current URL to the one given, when mounted.
import { Redirect } from '@47ng/chakra-next'
export default ({ loggedIn }) => (
<>{loggedIn ? <Text>Hello !</Text> : <Redirect to="/login" />}</>
)
By default, the redirection will be pushed onto the navigation history stack.
You can replace the history stack instead with the replace
prop:
import { Redirect } from '@47ng/chakra-next'
export default () => (
<>
<Redirect to="/home" replace />
</>
)
Next.js dynamic paths are also supported:
import { Redirect } from '@47ng/chakra-next'
export default () => (
<>
<Redirect to="/blog/[slug]" as="/blog/foo-bar" />
</>
)
If you want to redirect to an external link
(not an internal route), you will have to set the external
prop:
import { Redirect } from '@47ng/chakra-next'
export default () => (
<>
<Redirect to="https://example.com" external />
{/* You can also have the history replaced with external URLs: */}
<Redirect to="https://example.com" external replace />
</>
)
You can also pass transition options:
<Redirect to="/home" shallow scroll={false} />
Cards
import { Card, cardProps } from '@47ng/chakra-next'
export default () => (
<>
{/* Card as Box */}
<Card>I'm in a card</Card>
{/* Apply Card styles to a custom component */}
<MyChakraComponent {...cardProps} />
</>
)
Svg
Extends chakra.svg
with with:
- SVG namespace pre-filled
role="img"
import { Svg } from '@47ng/chakra-next'
export default () => (
<Svg
aria-labelledby="svg-demo-title svg-demo-desc"
viewBox="0 0 24 24"
display="block"
my={4}
mx="auto"
>
<title id="svg-demo-title">A red circle</title>
<desc id="svg-demo-desc">
Svg lets you style SVG container tags with Chakra UI style props.
</desc>
<circle fill="red" cx="12" cy="12" r="10">
</Svg>
)
Note: to use theme tokens for fills, strokes and other SVG properties, you must resolve them first:
import { useToken } from '@chakra-ui/react'
export default () => (
<Svg
aria-labelledby="svg-demo-title svg-demo-desc"
viewBox="0 0 24 24"
display="block"
my={4}
mx="auto"
fill={useToken('colors', 'red.500')} // Resolve theme tokens with `useToken`
>
<title id="svg-demo-title">A red circle</title>
<desc id="svg-demo-desc">
Svg lets you style SVG container tags with Chakra UI style props.
</desc>
<circle
// You can also use the CSS prop names directly:
fill="var(--chakra-colors-red.500)"
cx="12"
cy="12"
r="10"
>
</Svg>
)
NoSSR
Sometimes you want to render a component only on the client, and have a skeleton or fallback component rendered on the server, whether for SSR or static output.
import { NoSSR } from '@47ng/chakra-next'
export default () => (
<>
<NoSSR>This is only rendered on the client</NoSSR>
{/* Skeleton is rendered on SSR/SSG, TheRealThing is rendered on the client.*/}
<NoSSR fallback={<Skeleton />}>
<TheRealThing />
</NoSSR>
</>
)
Examples
Header with navigation links:
import { Box, Stack } from '@chakra-ui/core'
import { NavLink } from '@47ng/chakra-next'
export default () => (
<Box as="header">
<Stack as="nav" isInline>
<NavLink to="/features">Features</NavLink>
<NavLink to="/pricing">Pricing</NavLink>
<NavLink to="/docs">Documentation</NavLink>
</Stack>
</Box>
)
License
MIT - Made with