Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion bulma-ui/src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ export const NavbarBrand: React.FC<NavbarBrandProps> = ({
* Props for the NavbarItem component.
*
* @property {string} [className] - Additional CSS classes.
* @property {React.ElementType} [as] - Render as a custom component.
* @property {React.ElementType} [as] - Render as a custom component (e.g., a router link).
* @property {boolean} [active] - Whether the item is active.
* @property {(typeof validColors)[number] | 'inherit' | 'current'} [textColor] - Text color for the item.
* @property {(typeof validColors)[number] | 'inherit' | 'current'} [bgColor] - Background color for the item.
Expand All @@ -166,6 +166,8 @@ export interface NavbarItemProps
textColor?: (typeof validColors)[number] | 'inherit' | 'current';
bgColor?: (typeof validColors)[number] | 'inherit' | 'current';
children?: React.ReactNode;
// Allow router props like `to` when rendering via `as` (matches MenuItemProps)
[key: string]: unknown;
}

/**
Expand Down
17 changes: 17 additions & 0 deletions bulma-ui/src/components/__tests__/Navbar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { render, screen, fireEvent } from '@testing-library/react';
import type { ComponentProps } from 'react';
import Navbar from '../Navbar';
import { ConfigProvider } from '../../helpers/Config';

Expand Down Expand Up @@ -187,6 +188,22 @@ describe('Navbar.Item', () => {
expect(item).toHaveClass('navbar-item');
});

it('forwards router props like "to" to a custom "as" component', () => {
// Stand-in for a router link (e.g. react-router-dom's Link)
const RouterLink = ({
to,
...rest
}: { to: string } & ComponentProps<'a'>) => <a href={to} {...rest} />;
render(
<Navbar.Item as={RouterLink} to="/pricing" data-testid="item">
Pricing
</Navbar.Item>
);
const item = screen.getByTestId('item');
expect(item).toHaveAttribute('href', '/pricing');
expect(item).toHaveClass('navbar-item');
});

it('applies textColor and bgColor', () => {
render(
<Navbar.Item textColor="danger" bgColor="white" data-testid="item">
Expand Down
27 changes: 27 additions & 0 deletions docs/docs/api/components/navbar.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,33 @@ A more complex example with navigation links and a dropdown menu. The dropdown i

---

### Custom Link Component

Use the `as` prop on `Navbar.Item` to render a custom link component, such as a router link. Extra props like `to` are forwarded to the link component and type-check without casts, so client-side routing libraries integrate directly. See the [Routing guide](../../guides/features/routing.md) for the full patterns.

```tsx live
// import { Link } from 'react-router-dom';
function example() {
const Link = props => <a>{props.children}</a>;
return (
<Navbar>
<Navbar.Menu active>
<Navbar.Start>
<Navbar.Item as={Link} to="/">
Home
</Navbar.Item>
<Navbar.Item as={Link} to="/pricing">
Pricing
</Navbar.Item>
</Navbar.Start>
</Navbar.Menu>
</Navbar>
);
}
```

---

### Transparent Navbar

Example of a navbar with a transparent background. This is often used for navbars that overlay content, like images or videos, giving a more integrated look.
Expand Down
27 changes: 9 additions & 18 deletions docs/docs/guides/features/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,37 +40,28 @@ import { Menu } from '@allxsmith/bestax-bulma';

## Navbar items as router links

`Navbar.Item` accepts `as={Link}` the same way, and at runtime every extra prop (including
`to`) is forwarded to your link component. In **TypeScript**, however, `to` isn't part of
`Navbar.Item`'s prop type (it extends anchor attributes), so `<Navbar.Item as={Link} to="…">`
is a type error today. The recommended pattern is a one-line typed alias, declared once:
`Navbar.Item` works the same way — pass the router's link component via `as`, and `to` (or
any other router prop) is forwarded to it. Like `Menu.Item`, its prop type accepts extra
keys, so this compiles without errors or casts:

```tsx
import { Link, LinkProps } from 'react-router-dom';
import { Link } from 'react-router-dom';
import { Navbar } from '@allxsmith/bestax-bulma';

// One cast, reused everywhere — runtime behavior is unchanged.
const NavbarLink = Navbar.Item as React.FC<
React.ComponentProps<typeof Navbar.Item> & LinkProps
>;

<Navbar color="dark">
<Navbar.Menu active={open}>
<Navbar.Start>
<NavbarLink as={Link} to="/">
<Navbar.Item as={Link} to="/">
Home
</NavbarLink>
<NavbarLink as={Link} to="/pricing">
</Navbar.Item>
<Navbar.Item as={Link} to="/pricing">
Pricing
</NavbarLink>
</Navbar.Item>
</Navbar.Start>
</Navbar.Menu>
</Navbar>;
```

(Plain-JavaScript apps can skip the alias — `<Navbar.Item as={Link} to="/pricing">` just
works.)

## Buttons that navigate

`Button`'s `as` prop is polymorphic (any `React.ElementType`), so the same two options apply:
Expand Down Expand Up @@ -164,5 +155,5 @@ On Next.js **before 13**, `<Link>` required an `<a>` child by default — wrap i
- [Navbar](../../api/components/navbar.md) · [Menu](../../api/components/menu.md) ·
[Button](../../api/elements/button.md)
- `Button`/`Link` polymorphism landed in [#238](https://github.com/allxsmith/bestax/pull/238);
first-class `to` typing on `Navbar.Item` (dropping the cast alias above) is tracked in
first-class `to` typing on `Navbar.Item` landed via
[#306](https://github.com/allxsmith/bestax/issues/306).
8 changes: 3 additions & 5 deletions skills/bestax-layout-scaffold/references/layout-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,9 @@ document.documentElement.classList.add('has-navbar-fixed-top');
```

**Routing:** in a routed app, don't use `href="#"` — render items as the router's link
component. `Menu.Item as={Link} to="/x"` compiles without casts (its props allow extra keys);
`Navbar.Item as={Link}` forwards `to`
at runtime but needs a one-line typed alias in TypeScript (`Navbar.Item as React.FC<…Props &
LinkProps>`). Drive `active` from `useLocation().pathname`. Full patterns (including Buttons
that navigate and Next.js `href`): the docs guide at
component. `Menu.Item as={Link} to="/x"` and `Navbar.Item as={Link} to="/x"` both compile
without casts (their props allow extra keys). Drive `active` from `useLocation().pathname`.
Full patterns (including Buttons that navigate and Next.js `href`): the docs guide at
https://bestax.io/docs/guides/features/routing.

## Menu
Expand Down
Loading