Takazudo Modular Styleguide

MDX/InstagramEmbed

Default
Multiple Embeds
Reel Post
With Class Name

Component Source

instagram-embed.tsx

import type { FunctionComponent } from 'preact';

const toEmbedSrc = (url: string): string => {
  try {
    const urlObj = new URL(url);
    const allowedHosts = ['instagram.com', 'www.instagram.com'];

    if (!allowedHosts.includes(urlObj.hostname)) {
      throw new Error(`Invalid Instagram host: ${urlObj.hostname}`);
    }

    // Extract shortcode from /p/{shortcode}/ or /reel/{shortcode}/ URLs
    const match = urlObj.pathname.match(/^\/(p|reel)\/([A-Za-z0-9_-]+)/);
    if (!match) {
      throw new Error(`Could not extract shortcode from: ${urlObj.pathname}`);
    }

    const type = match[1];
    const shortcode = match[2];
    return `https://www.instagram.com/${type}/${shortcode}/embed/`;
  } catch (error) {
    throw new Error(`Invalid Instagram URL: ${url} - ${error}`, { cause: error });
  }
};

interface InstagramEmbedProps {
  url: string;
  className?: string;
}

const InstagramEmbed: FunctionComponent<InstagramEmbedProps> = ({ url, className = '' }) => (
  <div className="pb-vgap-lg">
    <div className={`border border-zd-white aspect-[4/5] lg:max-w-3/4 ${className}`}>
      <iframe
        src={toEmbedSrc(url)}
        title="Instagram embed"
        allowFullScreen
        loading="lazy"
        referrerPolicy="strict-origin-when-cross-origin"
        className={'block w-full h-full border-none'}
      ></iframe>
    </div>
  </div>
);

export { InstagramEmbed };

Story Source

instagram-embed.stories.tsx

import { InstagramEmbed } from './instagram-embed';
import type { ControlsMap } from '../../sub-packages/styleguide-v2/src/data/control-types';

/**
 * InstagramEmbed Component
 *
 * Embeds Instagram posts and reels in MDX articles.
 * Features:
 * - Supports post (/p/) and reel (/reel/) URL formats
 * - URL validation for instagram.com
 * - Lazy loading for performance
 */
export const meta = {
  title: 'MDX/InstagramEmbed',
};

export const controls: ControlsMap = {
  url: { type: 'text', default: 'https://www.instagram.com/p/DUlkwjdDdQS/' },
};

/**
 * Default - Standard Instagram post URL
 *
 * Uses the standard instagram.com/p/ format
 */
export const Default = {
  args: { url: 'https://www.instagram.com/p/DUlkwjdDdQS/' },
  render: ({ url }: { url: string }) => <InstagramEmbed url={url} />,
};

/**
 * Reel post format (/reel/)
 */
export const ReelPost = () => <InstagramEmbed url="https://www.instagram.com/reel/DUlkwjdDdQS/" />;

/**
 * With custom className
 */
export const WithClassName = () => (
  <InstagramEmbed
    url="https://www.instagram.com/p/DUlkwjdDdQS/"
    className="border-2 border-zd-link"
  />
);

/**
 * Multiple embeds in sequence
 */
export const MultipleEmbeds = () => (
  <div className="max-w-[800px]">
    <h3 className="text-zd-white pb-vgap-sm">Instagram 投稿</h3>
    <InstagramEmbed url="https://www.instagram.com/p/DUlkwjdDdQS/" />
    <h3 className="text-zd-white pb-vgap-sm">Instagram リール</h3>
    <InstagramEmbed url="https://www.instagram.com/reel/DUlkwjdDdQS/" />
  </div>
);